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