#haskell #monad-transformers
#haskell #монадные трансформаторы
Вопрос:
Я пытаюсь узнать о монадных трансформаторах, внедряя свои собственные. Код компилируется, если я использую newType DummyT m x y z = DummyT { runDummyT :: m (Dummy x y z) }
, но не если я использую GADT. Однако мне нужно использовать GADT, но это кажется более сложным. Я получаю эту ошибку:
Expecting one more argument to ‘m’
Expected a type, but ‘m’ has kind ‘* -> *’
In the first argument of ‘DummyT’, namely ‘m’
In the first argument of ‘Functor’, namely ‘(DummyT m x y)`
Я получаю ту же ошибку для экземпляров applicative и monad.
Почему я получаю эту ошибку? Любая помощь приветствуется.
моя монада:
instance Monad (Dummy x y) where
return = Return
(>>=) = Bind
data Dummy x y z where
Return :: z -> Dummy x y z
Bind :: Dummy x y z -> (z -> Dummy x y q) -> Dummy x y q
попытка преобразования:
instance Monad m => Functor (DummyT m x y) where
fmap = liftM
instance Monad m => Applicative (DummyT m x y) where
pure = return
(<*>) = ap
instance Monad m => Monad (DummyT m x y) where
return = Return
(>>=) = Bind
data DummyT m x y z where
Return :: z -> DummyT m x y z
Bind :: DummyT m x y z -> (z -> DummyT m x y q) -> DummyT m x y q
Ответ №1:
В
newType DummyT m x y z = DummyT { runDummyT :: m (Dummy x y z) }
очевидно m
* -> *
, что вид m
is применяется к типу.
В
data DummyT m x y z where
Return :: z -> DummyT m x y z
Bind :: DummyT m x y z -> (z -> DummyT m x y q) -> DummyT m x y q
m
не используется, поэтому GHC выводит kind *
, поскольку это самое простое. Возможно, это могло бы сделать это полиподобным, но не сделало.
Если вам нужен другой тип, явно попросите об этом:
data DummyT (m :: * -> *) x y z where
Return :: z -> DummyT m x y z
Bind :: DummyT m x y z -> (z -> DummyT m x y q) -> DummyT m x y q
Интересно, однако, имеет ли смысл не использовать m
здесь.
Комментарии:
1.
*
находится на медленном совпадении с забвением. Лучше импортироватьData.Kind
и использоватьType
.2. Спасибо, теперь он компилируется. Не могли бы вы объяснить, почему
m
это может не понадобиться?3. @datamoose Вы не использовали его в типах
Return
иBind
, кроме как в качестве аргументаDummyT
. Ни в коем случае мы не можем читатьm (some type)
так, как мы это делали вnewtype
определении.4. @datamoose, я подозреваю, что для того, чтобы сделать это монадным преобразователем, вам нужно добавить конструктор
Lift :: m a -> DummyT m x y a
. Лучше сначала изменить параметры вашего типа :DummyT x y m a
. Это позволит вам писатьinstance MonadTrans (DummyT x y) where lift = Lift
.