选择一个不确定的选择

时间:2014-08-04 18:33:43

标签: haskell monads monad-transformers state-monad non-deterministic

以下玩具示例通过调用函数anyFunction来计算非确定性数字,然后仅保留偶数选项。我怎么能写出一个类似的代码来保持最大的选择而不是偶数的选择呢?我需要一个不同的monad堆栈签名吗?

anyFunction :: StateT Int [] Int
anyFunction = undefined


test :: StateT Int [] Int
test = do
  s <- anyFunction
  put s
  v <- get
  if even v then return v else mzero

2 个答案:

答案 0 :(得分:2)

StateT Int [] Int可能不是你想要的。扩展定义我们可以看到它是Int -> [(Int, Int)]。当我们执行s <- lift [1, 2, 3, 4]时,我们为每个数字运行多个有状态操作,然后将返回值和已修改状态都收集到列表中。

这意味着这个monad无法使用lift计算列表的最大值,因为列表中的每个数字都有不同的状态(每个状态对其他状态都是不可见的)。

我们在mapMflipM处使用简单的State Int Int更好:

import Control.Monad
import Control.Monad.State.Strict

test :: State Int Int
test = do
    forM_ [1, 2, 3, 4] $ \n -> do
        modify $ max n
    get

这直接对应于计算最大值的通常命令计数器。

答案 1 :(得分:2)

你想要的是“在[]”下运行StateT可以说,获得Int的所有anyFunction结果,同时保留其余的StateT Int [] Int -> State Int [Int] monad尽可能多地堆叠。

您希望某个类型与Int类似的函数。这将获得所有StateT Int [] Int s,以便您可以计算最大值。

但是考虑到你的monad堆栈,你的功能很难实现。计算的每个分支路径都有自己的状态“线程”,但是当你将State Int [Int]减少到ListT (State Int) Int时,我们应该保留哪个“线程”状态?没有一种解决方案看起来很自然。

现在,假设您正在使用runListT monad堆栈。这里所有分支都共享相同的“线程”状态。专门化ListT (State Int) Int -> State Int [Int],它具有签名anyFunction :: ListT (State Int) Int anyFunction = undefined test :: ListT (State Int) Int test = do -- preserve non-ListT parts of the stack -- and re-wrap the result into a list s <- ListT $ liftM (\l -> [maximum l]) $ runListT anyFunction put s v <- get if even v then return v else mzero

示例可以写成如下:

{{1}}