如何使用递归定义遍历Monad并收集结果?

时间:2018-05-10 15:39:29

标签: haskell recursion monads monad-transformers

我实现了monad变换器MaybeT

newtype MaybeT m a =
    MaybeT { runMaybeT :: m (Maybe a) }

然后,我写了一个monad用于回溯。

newtype BackT m a =
    BackT { unBackT :: MaybeT m (a, BackT m a) }

这里,Back m a具有递归定义。

在我看来,有同构。

                 unBackT
BackT m a <-------------------> MaybeT m (a, BackT m a)
            BackT(constructor)    

                              runMaybeT
MaybeT m (a, BackT m a) <------------------> m (Maybe (a, BackT m a))
                         MaybeT(constructor)

因此,我实际上得到了像

这样的东西
m (Just(1, m (Just(2, m (Just(3, m (Just(4, Nothing))))))))

在上面给出的例子中,有4个计算(Monad是计算?)。我需要一些名为runBackT的内容来使用[]来收集它们。

感谢@rampion的回答,我删除了一些毫无意义的问题。

  • 结果的类型是什么?它应该取决于m(答案:结果类型应为m a。)
  • 如何收集所有结果?是否可能?(答案:Monad m a并不能保证有办法获得&#34;解包&#34;类型。)
  • 如何在示例中收集所有参数,如1,2,3,4。它的类型应为[a]。这样的BackT m a -> [a]函数是否存在?或者,我们只能获得m [a]吗? (答案:只有BackT m a -> m [a] 可能存在。)

更新

Monad可以分为两类:&#34;打开monad&#34; (例如[]Maybe)和&#34;封闭的monad&#34; (如IO)。 &#34;打开monad&#34;具有类型m a -> b的函数来打开它们。 e.g。

showMaybe :: (Show a) => Maybe a -> String
showMaybe mx = case mx of
    Nothing -> "Nothing"
    Just x -> show x
  1. 如何实施(Monad m, Show m) => BackT m a -> [String]
  2. 更一般地说,Monad m => (m a -> b) -> BackT m a -> [b]
  3. 在什么条件下,Monad m => BackT m a -> [m a]是否存在? BackT m a序列计算m a通过交叉递归定义递归。如何将其更改为迭代[m a]?如果存在,如何实现呢?我们可以将m a -> b映射到[m a],问题(2)将会得到解决。
  4. Monad m => (m a -> a) -> BackT m a -> m [a]?只需用构造函数m包装问题(2)的结果。
  5. 因此,关键点是问题(3)。

    对我来说最困难的部分是BackT m a的递归定义。如果您能展示工具或分享一些建议,我会很感激。

    仅针对问题(3)的答案是可以的。

    更新

    感谢@rampion的评论,ListT from list-t package回答了我的问题。

1 个答案:

答案 0 :(得分:2)

  

如何在示例中收集1, 2, 3, 4之类的所有参数。它的类型应该是[a]。这样的BackT m a -> [a]函数是否存在?或者我们只能获得m [a]

首先想到这一点。

我们当然可以获得BackT m a的{​​{1}}值:

Monad m

凭借Prelude> emptyBackT = BackT (MaybeT (return Nothing)) Prelude> :t emptyBackT emptyBackT :: Monad m => BackT m a 的强大功能,我们可以将fmap转换为m a 任何BackT m a的{​​{1}}:

Functor m

因此,如果我们有办法转换任何Prelude> lift ma = BackT (MaybeT (fmap (\a -> Just (a, emptyBackT)) ma)) Prelude> :t lift lift :: Monad m => m a -> BackT m a ,我们可以将其与BackT m a -> [a]结合使用,以获得lift的{​​{1}}!

但我们知道我们不能在Haskell中做到这一点。一些仿函数(如m a -> [a]Functor m)展开,但还有其他仿函数(如[])不能。

因此Maybe需要输入IO类型。

至于实施,这里有一些主要问题。

你有runBackTBackT m a -> m [a]的同构,所以

  • 假设BackT m a已经实施,您可以实施m (Maybe (a, BackT m a))吗?
  • 假设runBackT :: BackT m a -> m [a]已经实施,您可以实施consBackT :: a -> BackT m a -> m [a]吗?
  • 假设runBackT :: BackT m a -> m [a]已经实施,您可以实施unwrapBackT :: Maybe (a, BackT m a) -> m [a]吗?

(提示:我在主要问题中使用的类型不完整)