Какой явный пример монады без монада-трансформатора?

Трансформаторы Monad известны для всех стандартных монадов (Reader, Writer, State, Cont, List и т.д.), Но каждый из этих монадных трансформаторов работает несколько иначе. Не существует общего метода или формулы для построения монадного трансформатора с определением конструктора типа с экземпляром монады. Таким образом, не гарантируется, что тип данных монады, разработанный в соответствии с некоторыми произвольными бизнес-требованиями, будет иметь трансформатор монады. Есть ли такой явный пример?

Связанных с работой

Другой вопрос объясняет, что функторная композиция из двух монад не обязательно является монадой. См. Также этот вопрос. Эти примеры не отвечают на данный вопрос - они просто иллюстрируют проблему отсутствия общего метода построения монадного трансформатора. Эти примеры показывают, что, учитывая две монады M и N, мы иногда обнаруживаем, что M (N a) является монадой, иногда N (M a) является монадой, а иногда и не будет монадой. Но это не показывает, как построить монадный трансформатор для M или N, и не существует ли вообще.

Ответ на другой вопрос утверждает, что монада IO не может иметь трансформатор монады, потому что если бы у него был один IOT, мы могли бы применить IOT к List, а затем, подняв пустой список (lift []) в результирующую монаду, пришлось бы отменить сторону эффекты, выполненные "раньше" монадой IO. Этот аргумент основан на идее о том, что монада IO "фактически выполняет" побочные эффекты, которые, по-видимому, не могут быть отменены. Однако монада IO не является явным конструктором типов.

обсуждение

В каждом примере, где явно задан тип монады, может быть найден какой-то монадный трансформатор - иногда с определенной изобретательностью. Например, трансформатор ListT который существовал в библиотеке Haskell, относительно недавно был обнаружен некорректным тонким способом, но проблема в конечном итоге была устранена путем изменения определения ListT.

Стандартными примерами монадов без трансформаторов являются монады, такие как IO, которые на самом деле не определены явным конструктором типов. IO - непрозрачный "магический" тип, определенный библиотекой как-то на низком уровне. Кажется очевидным, что нельзя определить IO как явный конструктор типов с экземпляром монады, заданным чистыми функциями. Пример IO показывает, что монадный трансформатор может не существовать, если мы разрешаем экземпляру монады содержать скрытый низкоуровневый код с нечистыми побочными эффектами. Итак, остановим наше внимание на монадах, реализованных с использованием чистых функций.

Кажется, что не существует алгоритма, который автоматически выводит монадные трансформаторы из исходного кода монады. Мы даже знаем, что это всегда возможно?

Чтобы было более ясно, что я подразумеваю под "явным примером" монады: предположим, я утверждаю, что

 type Q u v a = ((u -> (a, Maybe a)) -> v) -> u -> (a, Maybe a)

может иметь законный экземпляр Monad отношению к параметру типа a, и я создаю исходный код для реализации экземпляра Monad для Q uv когда return и join чистые функции. Знаем ли мы тогда, что Q uv имеет монадный трансформатор QT uv такой, что QT uv Id эквивалентен Q uv, и имеют место законы монадных трансформаторов? Знаем ли мы, как построить QT явно? Я не.

Чтобы решить этот вопрос, нам нужно либо

  • продемонстрировать алгоритм, который найдет монадный трансформатор из произвольного заданного типа конструктора и заданной реализации экземпляра монады; например, заданный type F a = r → Either (a, a) (a, a, Maybe a) кода type F a = r → Either (a, a) (a, a, Maybe a) и реализация экземпляра монады для этого, чтобы найти код для монадного трансформатора; давайте ограничимся типа конструктора, изготовленные из любой комбинации ->, кортеж, и Either для простоты; или же
  • чтобы продемонстрировать контрпример: явный конструктор типа монады, заданный явным определением кода, например, type F a = r → Either (a, a, a) (a, a, Maybe a) или что угодно, так что это законный Monad, с экземпляром Monad заданный чистыми функциями, но мы можем доказать, что F не имеет монадного трансформатора.

Ответы

Ответ 1

Это не ответ, но он слишком большой для комментария. Мы можем написать

{-# LANGUAGE GeneralizedNewtypeDeriving
  , DeriveFunctor #-}

import Control.Monad.Free

-- All the IO primops you could ever need
data IOF a = PutStrLn String a
           | GetLine (String -> a)
           deriving Functor

newtype MyIO a = MyIO {unMyIO :: Free IOF a}
  deriving (Functor, Applicative, Monad)

Но мы можем сделать из этого трансформатор монады:

import Control.Monad.Trans.Free

newtype IOT m a = IOT {unIOT :: FreeT IOF m a}
  deriving (Functor, Applicative, Monad, MonadTrans)

Поэтому я действительно не думаю, что даже IO исключается, хотя изоморфизм в этом случае не является "внутренним".