haskell 单子迭代

vxbzzdmp  于 2022-11-14  发布在  其他
关注(0)|答案(2)|浏览(182)

我很难理解单子的迭代行为是如何从它的definition导出的。

instance Monad [] where
  m >>= f  = concatMap f m
  return x = [x]
  fail s   = []

我所读到的讨论似乎忽略了>>=如何创建控制结构的问题,如do符号所示:

allEvenOdds :: Int -> [(Int,Int)]
allEvenOdds n = do
  evenValue <- [2,4 .. n]               
  oddValue <- [1,3 .. n]                
  return (evenValue,oddValue)

这是内置在Haskell中的吗,就像我假设的IO单子与实际i/o的接口一样?

nszi6y05

nszi6y051#

没有任何内置的东西,所有的一切都是你引用的Monad示例的简单结果(而且,由于这个例子使用do表示法,它是如何简化为>>=运算符的用法的):

allEvenOdds n = do
  evenValue <- [2,4 .. n]               
  oddValue <- [1,3 .. n]                
  return (evenValue,oddValue)

-- desugaring the do notation
allEvenOdds n =
  [2,4 .. n] >>= \evenValue ->
  [1,3 .. n] >>= \oddValue ->
  return (evenValue, oddValue)

-- using the list instance of Monad to replace >>= and return
allEvenOdds n =
  concatMap (\evenValue ->
    concatMap (\oddValue -> [(evenvalue, oddValue)]) [1,3 .. n]
  ) [2,4 .. n]

您可以很容易地看到“迭代”两个列表,并得到一个包含所有(偶数,奇数)对的列表,其中的值取自两个列表。
在高层次上,我们可以说单子导致迭代,仅仅是因为concatMapmap一样,对列表中的每个元素执行给定的函数,所以它隐式地迭代列表。

vuktfyat

vuktfyat2#

Monad类型类模型的列表示例 * 非确定性 *:可以将每个var <- someList看作是一个for循环,就像Python中一样。
do表示法被去糖化为[2,4 .. n] >>= (\evenValue -> [1, 3 .. n] >>= (\oddValue -> return (evenValue, oddValue))),所以这相当于Python中的一些内容:

result = []
    for evenValue in range(2, n, 2):
        for oddValue in range(1, n, 2):
            result.append((evenValue, oddValue))

或者使用列表解析:

result = [
        (evenValue, oddValue)
        for evenValue in range(2, n, 2)
        for oddValue in range(1, n, 2)
    ]

这是因为对于instance Monad [],表达式[2,4 .. n] >>= (\evenValue -> [1, 3 .. n] >>= (\oddValue -> return (evenValue, oddValue)))因此等效于:

concatMap (\evenValue -> [1, 3 .. n] >>= (\oddValue -> return (evenValue, oddValue))) [2,4 .. n]

从而:

concatMap (\evenValue -> concatMap (\oddValue -> [(evenValue, oddValue)]) [1, 3 .. n]) [2,4 .. n]

但是,do符号并没有“硬连接”到IOIO只是Monad的一个示例,它的实现方式是一个IO操作在第二个之前运行。对于列表,它的实现方式等同于跨越Python for循环。

相关问题