如何用List monad建模非确定性?

时间:2013-12-17 16:01:32

标签: haskell f# functional-programming monads non-deterministic

任何人都可以解释(更好地使用简单的英语示例)列表monad可以做什么来模拟非确定性计算?即问题是什么以及列表monad可以提供什么解决方案。

4 个答案:

答案 0 :(得分:37)

这是一个基于抛硬币的例子。问题如下:

  

您有两个硬币,标有有偏见 Fair Biased 硬币有两个头, Fair 硬币有一个头和一个尾。随机选择其中一个硬币,扔掉并观察结果。如果结果是头部,那么您选择偏见硬币的概率是多少?

我们可以在Haskell中对此进行建模,如下所示。首先,你需要硬币及其面孔的类型

data CoinType = Fair | Biased deriving (Show)

data Coin = Head | Tail deriving (Eq,Show)

我们知道抛出一枚公平的硬币可能会出现HeadTail,而有偏见的硬币总会出现Head。我们用可能的替代方案列表对此进行建模(隐含地,每种可能性都是可能的)。

toss Fair   = [Head, Tail]
toss Biased = [Head, Head]

我们还需要一个能够随机选择公平或有偏见的硬币的功能

pick = [Fair, Biased]

然后我们像这样把它们放在一起

experiment = do
  coin   <- pick         -- Pick a coin at random
  result <- toss coin    -- Toss it, to get a result
  guard (result == Head) -- We only care about results that come up Heads
  return coin            -- Return which coin was used in this case

请注意,虽然代码读起来就像我们只是运行一次实验,但是列表monad正在建模非确定性,并实际上遵循所有可能的路径。因此结果是

>> experiment
[Biased, Biased, Fair]

因为所有可能性都是同等可能的,我们可以得出结论,我们有2/3的机会拥有有偏见的硬币,只有1/3的机会我们拥有公平的硬币。

答案 1 :(得分:17)

当我们说它是非决定论时,它意味着它有多个值。

Learn You A Haskell书很好地解释了这一点:

  

像5这样的值是确定性的。它只有一个结果,我们知道   到底是什么。另一方面,像[3,8,9]这样的值包含   几个结果,所以我们可以将其视为一个实际上很多的值   价值在同一时间。使用列表作为applicative functor展示   这种非决定论很好:

ghci> (*) <$> [1,2,3] <*> [10,100,1000]  
[10,100,1000,20,200,2000,30,300,3000]
  

左侧乘法元素的所有可能组合   包含右侧列表中元素的列表包含在结果中   名单。在处理非决定论时,有很多选择   我们可以做,所以我们只是尝试所有这些,结果是一个   非确定性的价值,只有它有更多的结果。

很好地列出monad模型非确定性。它的实例是这样的:

instance Monad [] where  
    return x = [x]  
    xs >>= f = concat (map f xs)  
    fail _ = [] 

因此,当您提供非确定性值时,它将产生另一组非确定性值:

ghci> [3,4,5] >>= \x -> [x, x * 2]
[3,6,4,8,5,10]

答案 2 :(得分:10)

列表monad可以表示“来自非确定性计算的所有可能结果”。例如,函数

f x = [x, x + 1, x + 2]

可以解释为一个非确定性计算,它采用x并返回xx+1x+2之一。

功能

g x = [2 * x, 3 * x]

可以解释为一个非确定性计算,它采用x并返回2 * x3 * x。这两个非确定性计算的“组成”应该是另一个非确定性计算,它采用x,将其转换为xx + 1x + 2之一,然后将它加倍或三倍。因此,就列表而言,结果应该是所有六种可能性的列表

现在

g =<< f x = [2 * x, 3 * x, 2 * (x + 1), 3 * (x + 1), 2 * (x + 2), 3 * (x + 2)]

所以这确实模仿了我们所期望的非决定论。

(使用列表进行非确定性有一些尴尬,因为它们也有元素的排序。“set monad”可能是一种更自然的非确定性建模方法。列表当然包含 用于建模非确定性的信息,但排序意味着我们有更多信息而不是必要的。)

编辑:实际上我写的只是使用列表应用实例。要获得完全利用monadic接口的东西,您需要一个返回大量结果的计算,这些结果取决于其输入,例如

g 0 = [1000, 1001]
g x = [2 * x, 3 * x, 4 * x]

虽然承认这是一个完全随意且无动机的例子!

答案 3 :(得分:9)

因此,明确定义'非确定性'在这里意味着什么是很重要的,因为它与在非确定性算法中可能被感知的方式不完全相同。这里捕获的意义是计算分支 - 可能有多个状态,系统可以在任何特定点移动。

列表对此进行建模,因为它们只包含多个元素。更重要的是,monadic理解为我们提供了一种组合非确定性结果的方法 - 即模拟一次探索所有分支。