使用List Monad vs fmap

Car*_*bon 1 monads haskell

列表monad是否有任何实际用途,不仅仅是滚动到fmap?你何时会使用list over fmap与list monad?

例如,你可以这样做[1,2,3] >>= return . ( + 1)但是(+1) <$> [1,2,3]- 你什么时候使用bind而不返回列表?

Rei*_*chs 12

将bind与return一起使用相当于使用fmap.确实,

fmap f m = m >>= return . f
Run Code Online (Sandbox Code Playgroud)

无法用fmap重现的bind的使用正是那些不涉及这种return的使用.为列表提供一个(希望)有趣的例子,让我们来谈谈L-Systems.

L系统由Aristid Lindenmeyer于1968年创建.作为重写系统,它们从一个简单的对象开始,并使用一组重写规则制作重复替换它的一部分.它们可用于生成分形和其他自相似图像.无上下文,确定性L系统(或D0L)由字母表,公理和生产规则集合的三重定义.

对于我们的字母表,我们将定义一个类型:

data AB = A | B deriving Show
Run Code Online (Sandbox Code Playgroud)

对于我们的公理或起始状态,我们将使用这个词[A, B].

myAxiom = [A, B]
Run Code Online (Sandbox Code Playgroud)

对于我们的规则,我们需要一个从单个字母到一系列字母的地图.这是类型的函数AB -> [AB].我们来使用这个规则:

myRule :: AB -> [AB]
myRule A = [A, B]
myRule B = [A]
Run Code Online (Sandbox Code Playgroud)

要应用规则,我们必须使用其生产规则重写每个字母.我们必须同时为单词中的所有字母执行此操作.方便的是,这正是>>=列表的作用:

apply rule axiom = axiom >>= rule
Run Code Online (Sandbox Code Playgroud)

现在,让我们将规则应用于我们的公理,生成L系统的第一步:

> apply myRule myAxiom
> [A, B, A]
Run Code Online (Sandbox Code Playgroud)

这是Lindenmeyer的原始L系统,用于模拟藻类.我们可以迭代看它的进展:

> mapM_ print . take 7 $ iterate (>>= myRule) myAxiom
[A,B]
[A,B,A]
[A,B,A,A,B]
[A,B,A,A,B,A,B,A]
[A,B,A,A,B,A,B,A,A,B,A,A,B]
[A,B,A,A,B,A,B,A,A,B,A,A,B,A,B,A,A,B,A,B,A]
[A,B,A,A,B,A,B,A,A,B,A,A,B,A,B,A,A,B,A,B,A,A,B,A,A,B,A,B,A,A,B,A,A,B]
Run Code Online (Sandbox Code Playgroud)

通常,绑定列表是concatMap,并且当您想要将映射与串联组合时,可以精确地使用它.另一种解释是列表表示非确定性选择,并且通过从列表中选择一次可能性来绑定函数.例如,滚动骰子:

do
  d1 <- [1..6]
  d2 <- [1..6]
  return (d1, d2)
Run Code Online (Sandbox Code Playgroud)

这提供了滚动2d6的所有可能方法.