Haskell中的函数映射到MonadTrans?

Haskell中的函数映射到MonadTrans?,haskell,monads,Haskell,Monads,我最近决定开始使用monad转换,而不是堆叠我的monad,因为这样做似乎是正确的。不管怎样,我以前真的没有堆积多少单子。我(我想)得到了它背后的想法和lift函数,据我所知,它是转换的一种return(将底层monad中的某些内容放入转换后的monad) 到目前为止还不错,但是我没有看到任何类似于monad转换的fmap函数的东西。让我给你举个例子。假设我有一个自定义monad,m,我在它上面使用了StateT转换,因此使用类型StateT s m a而不是m(State s a) 现在,碰巧

我最近决定开始使用monad转换,而不是堆叠我的monad,因为这样做似乎是正确的。不管怎样,我以前真的没有堆积多少单子。我(我想)得到了它背后的想法和
lift
函数,据我所知,它是转换的一种
return
(将底层monad中的某些内容放入转换后的monad)

到目前为止还不错,但是我没有看到任何类似于monad转换的
fmap
函数的东西。让我给你举个例子。假设我有一个自定义monad,
m
,我在它上面使用了
StateT
转换,因此使用类型
StateT s m a
而不是
m(State s a)

现在,碰巧在我的monad
m
中,我有一个函数可以转换monadic元素(事实上,它是monad的构造函数之一,如果您需要我提供的详细信息的话),同时在某种意义上保留底层值:
myFunc::ma->ma

因此,我正在构建一个递归函数
recFunc::State sa->[t]->m(State sa)
,它看起来类似于这样:

recFunc :: State s a -> [t] -> m (State s a)
recFunc x [] = return x
recFunc x (t:ts) = myFunc (recFunc x ts)
但是如果我尝试使用monad转换来复制它,我会遇到问题,因为我找不到方法将
myFunc
插入到混合中。无论您是将输入写入
状态sa
还是写入
状态标识a
(哪一种更精确?)

因此,我要寻找的是类似于(发明的,不知道如何实现,如果可能的话)以下功能的东西:

transmap :: (MonadTrans t, Monad m) => (forall b. m b -> m b) -> t m a -> t m a
transmap = ???

transreturn :: (MonadTrans t, Monad m) => m (t Identity a) -> t m a
transreturn = ???
fromTrans :: t m a -> m (t Identity a)
toTrans :: m (t Identity a) -> t m a
我觉得我应该能够使用
lift
定义这些,但老实说,我不知道如何定义

如果我有他们,那么我可以这样做:

recFuncT :: StateT s Identity a -> [t] -> StateT s m a
recFuncT x [] = transreturn (return x)
recFuncT x (t:ts) = transmap myFunc (recFuncT x ts)
也许我真正想要的是更基本的东西。我希望
tma
m(t恒等式a)
之间的假定同构是明确的,因此我正在寻找函数:

transmap :: (MonadTrans t, Monad m) => (forall b. m b -> m b) -> t m a -> t m a
transmap = ???

transreturn :: (MonadTrans t, Monad m) => m (t Identity a) -> t m a
transreturn = ???
fromTrans :: t m a -> m (t Identity a)
toTrans :: m (t Identity a) -> t m a
就我所理解的monad transformers而言,这些函数应该一直存在,并且相当简单,对吗

有了这些,我显然可以实现
transmap
transreturn

transmap :: (MonadTrans t, Monad m) => (forall b. m b -> m b) -> t m a -> t m a
transmap f x = toTrans (f (fromTrans x))

transreturn :: (MonadTrans t, Monad m) => m (t Identity a) -> t m a
transreturn = toTrans
我确信我忽略了一些显而易见的事情。请给我指一下


谢谢。

从评论中的讨论可以看出,您真正想要的似乎是自定义单子的单子转换器,然后应用于基本单子
状态
。换句话说,如果您的自定义单子“几乎”是一个列表:

其变压器版本应具有以下类型:

newtype ListishT m a = ListishT [m a]
因此,您的最终monad transformer堆栈将是:

type M s = ListishT (State s)
这和你的单子堆栈是同构的

[State s a]  AKA  Listish (State s a)
但是,请确保不要过度概括从底层monad创建转换器的模式。而一些单子的变压器:

newtype List a = List [a]
newtype Reader r a = Reader (r -> a)
通过将“
a
”替换为“
ma
”,可以合理地导出:

其他类型的变压器派生方式不同。例如:

newtype State s a = State (s -> (a, s))
newtype Writer w a = Writer (a, w)
给出:

特别是,
IO
没有monad转换器,因为

newtype BadIOT m a = BadIOT (IO (m a))

正如你所指出的,这是愚蠢的。

编辑:以下所有内容都毫无意义。我把它打穿了。下面的回答很好

作为记录,我的最终解决方案不是使用或实现monad转换器,而是简单地实现以下函数:(我的自定义monad称为
EnumProc
):

(…>>=)::Monad m=>EnumProc(ma)->(a->mb)->EnumProc(mb)
en..>>=f=en(>>=f)
infixl 7..>>=
这使我能够在保持外部monad结构的同时,在monad内部处理monadic计算。当一个
fmap
就足够了时,我自己也很惊讶


然后我使用
EnumProc(statea)
作为贯穿全文的类型。

过了一会儿,我终于找到了我从一开始就想要的东西。我可以完全按照我想要的方式使用StateT,它的语义也完全符合我的想法,但是我没有很好地解释它(并且在我写的东西中加入了错误)

回到我原来的帖子,我不需要一个
状态
作为输入,
状态
/
状态
单子已经包含了单子元素中的输入。因此,我需要的是一个函数
recFuncT::[t]->StateT s m a
,它的行为相当于以下非变压器函数:

recFunc :: a -> [t] -> m (State s a)
recFunc x [] = return (return x)
recFunc x (t:ts) = myFunc (recFunc x ts)
它可以使用构造函数
StateT
runStateT
直接实现。这是:

recFuncT :: a -> [t] -> StateT m s a
recFuncT x [] = return x
recFuncT x (t:ts) = StateT (\s -> myFunc (runStateT (recFuncT x ts) s))
此外,功能
transmap
通常也可以实现,至少对于
StateT

transmap :: Monad m => (forall b. m b -> m b) -> StateT s m a -> StateT s m a
transmap f st = StateT (\s -> f (runStateT st s)
然后我们就可以很好地用它来编写
recFuncT

recFuncT :: a -> [t] -> StateT m s a
recFuncT x [] = return x
recFuncT x (t:ts) = transmap myFunc (recFuncT x ts)

我意识到这与我最初包含的代码并不匹配,但它确实符合我试图呼吁的总体原则,即
StateT
转换器就像是将状态添加到我的monad
m
,因此可以在
m(状态sa)上执行的任何操作
级别可以在
StateT s m a
级别完成。

您正在寻找的一个概念可以在
mmorph
包中找到:

class MFunctor t where
  -- The argument is generally required to be a monad morphism,
  -- but some instances will work sensibly when it's not.
  hoist :: Monad m => (forall x. m x -> n x) -> t m a -> t n a

这比您的版本更通用一些,因为它允许替换底层的monad。

状态sa==StateT s Identity a
,因此
StateT s ma
m(StateT s Identity a)
是两件不同的事情。一个同构于
m(s->(a,s))
,另一个同构于
s->m(a,s)
@chepner,这是一个公平的观点,但即使这是真的,它仍然不能解决我的高级问题,即:我假设如果一个单子有一个相关的转换器,然后,你可以通过堆叠单子来做任何事情,你可以通过使用变压器来做,称之为“变压器原理”。所以我想做的是,你可以通过叠加monad来实现
transmap :: Monad m => (forall b. m b -> m b) -> StateT s m a -> StateT s m a
transmap f st = StateT (\s -> f (runStateT st s)
recFuncT :: a -> [t] -> StateT m s a
recFuncT x [] = return x
recFuncT x (t:ts) = transmap myFunc (recFuncT x ts)
class MFunctor t where
  -- The argument is generally required to be a monad morphism,
  -- but some instances will work sensibly when it's not.
  hoist :: Monad m => (forall x. m x -> n x) -> t m a -> t n a