【发布时间】:2012-12-14 19:10:09
【问题描述】:
我想在 haskell 中构建一个不确定的 monad 转换器,我相信它的行为不同于 ListT 和 http://www.haskell.org/haskellwiki/ListT_done_right 提出的替代 ListT。其中第一个将 monad 与项目列表相关联;第二个将 monad 与单个项目相关联,但具有给定元素中的 monadic 动作影响列表后续槽中的 monadic 元素的属性。目标是构建一个形式的单子变换器
data Amb m a = Cons (m a) (Amb m a) | Empty
这样列表中的每个元素都有自己的 monad 与之关联,并且连续的元素具有独立的 monad。在这篇文章的最后,我稍微演示了这个 monad 应该给出的那种行为。如果您知道如何获得 ListT 的一些变体来提供这种行为,那也会很有帮助。
以下是我的尝试。它不完整,因为 unpack 函数未定义。我该如何定义它?这是定义它的一次不完整的尝试,但是当 monad m 包含 Empty Amb 列表时,它没有处理这种情况:
unpack :: (Monad m) => m (Amb m a) -> Amb m a
unpack m = let first = join $ do (Cons x ys) <- m
return x
rest = do (Cons x ys) <- m
return ys
in Cons first (unpack rest)
完整(不完整)代码:
import Prelude hiding (map, concat)
import Control.Monad
import Control.Monad.Trans
data Amb m a = Cons (m a) (Amb m a) | Empty
infixr 4 <:>
(<:>) = Cons
map :: Monad m => (a -> b) -> Amb m a -> Amb m b
map f (Cons m xs) = Cons y (map f xs)
where y = do a <- m
return $ f a
map f Empty = Empty
unpack :: m (Amb m a) -> Amb m a
unpack m = undefined
concat :: (Monad m) => Amb m (Amb m a) -> Amb m a
concat (Cons m xs) = (unpack m) `mplus` (concat xs)
concat Empty = Empty
instance Monad m => Monad (Amb m) where
return x = Cons (return x) Empty
xs >>= f = let yss = map f xs
in concat yss
instance Monad m => MonadPlus (Amb m) where
mzero = Empty
(Cons m xs) `mplus` ys = Cons m (xs `mplus` ys)
Empty `mplus` ys = ys
instance MonadTrans Amb where
lift m = Cons m Empty
期望行为示例
这里,基本单子是State Int
instance Show a => Show (Amb (State Int) a) where
show m = (show . toList) m
toList :: Amb (State Int) a -> [a]
toList Empty = []
toList (n `Cons` xs) = (runState n 0 : toList xs)
x = (list $ incr) >> (incr <:> incr <:> Empty)
y = (list $ incr) >> (incr <:> (incr >> incr) <:> Empty)
main = do
putStr $ show x -- | should be [2, 2]
putStr $ show y -- | should be [2, 3]
谢谢。
更新:为什么 LogicT 不按我的意愿做事的一个例子。
这是 LogicT 在上面的简单示例中所做的:
import Control.Monad
import Control.Monad.Logic
import Control.Monad.State
type LogicState = LogicT (State Int)
incr :: State Int Int
incr = do i <- get
put (i + 1)
i' <- get
return i'
incr' = lift incr
y = incr' >> (incr' `mplus` incr')
main = do
putStrLn $ show (fst $ runState (observeAllT y) 0) -- | returns [2,3], not [2,2]
【问题讨论】:
-
你看过logict吗?
-
只是一个注释,在你不完整的
unpack,first = do { (Cons x _) <- m; x }。您不需要join和return的额外层。 -
@DanielWagner 根据您的建议,我查看了 logict 并在帖子末尾添加了一个示例,说明了为什么我认为 logict 不能满足我的要求。
-
@Eyal 很高兴您添加了示例。
StateT已经做了你想做的事。
标签: haskell monad-transformers non-deterministic monadplus