6

我目前正在编写一个项目,我大量使用了ListTmonad 转换器。使用普通列表时,实现非确定性非常容易。但是,一旦我不得不将我的代码转换为1ListT,它就会变得更加复杂。

举个简单的例子:从[a]到转换ListT a实际上需要组合两个函数:

conv :: (Monad m) => [a] -> ListT m a
conv = ListT . return

虽然它很简单,但我很惊讶它还没有。

问题:

  • 有没有更好的方法来处理需要单子变压器的不确定性?
  • 是否有任何技术/库可以在列表和列表之间来回转换干净ListT

1确切的原因很复杂,所以我真的不想过多阐述。

4

2 回答 2

6

我认为没有任何图书馆可以解决这个问题。conv毕竟,这是一个非常简单的函数,反之亦然runListT

conv类似于liftMaybe使用时经常需要的MaybeT

liftMaybe :: (Monad m) => Maybe a -> MaybeT m a
liftMaybe = MaybeT . return

我建议将其命名为liftList. 1

就非确定性更好的 monad 转换器而言,我建议查看基于 Oleg转换器的logictLogicT包,它是一个基于延续的回溯逻辑 monad,具有一些有用的操作。作为奖励,因为[]是 的一个实例MonadLogic,所以这些操作也适用于列表。


1有趣的是,我们可以定义一个泛化 和 模式的conv函数liftMaybe

import Data.Foldable (Foldable)
import qualified Data.Foldable as F

choose :: (Foldable t, MonadPlus m) => t a -> m a
choose = F.foldr (\a b -> return a `mplus` b) mzero

这可能会让你的代码很混乱,所以我不建议使用它:)

于 2012-02-09T16:40:02.033 回答
0

几个月后我才遇到这个问题,因为我想知道类似的事情。所以我想出了以下内容:

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}

import Control.Monad.Trans.Class
import Control.Monad.Trans.Maybe
import Control.Monad.Trans.List


-- | Minimal implementation: either joinLift or joinT
class (MonadTrans t, Monad m) => MonadTransJoin t m | m -> t, t -> m where
    joinLift :: (Monad m', Monad (t m')) => m' (m a) -> t m' a
    joinLift = joinT . lift

    joinT :: (Monad m', Monad (t m')) => t m' (m a) -> t m' a
    joinT = (>>= (joinLift . return))


instance MonadTransJoin MaybeT Maybe where
    joinLift = MaybeT
    joinT = (>>= maybe mzero return)

instance MonadTransJoin ListT [] where
    joinLift = ListT
    joinT = (>>= foldr mcons mzero)
        where mcons x xs = return x `mplus` xs

到目前为止一切都很好——我joinTListT/[]对的方法看起来与 ehird 的choose.

但问题在于,monad 转换器和其行为赋予其基本 monad 的 monad 之间实际上没有统一的接口。我们有MaybeT :: m (Maybe a) -> MaybeT m aand ListT :: m [a] -> ListT m a,但是我们有 OTOH StateT :: (s -> m (a, s)) -> StateT s m a。我不知道是否有办法解决这个问题——这当然需要

于 2012-08-07T08:19:38.867 回答