2014-10-30 61 views
4

我刚开始学习Haskell在几个星期前,我看到了这一点:这是如何阻止工作的?

moves = do 
    f <- [(+), subtract] 
    g <- [(+), subtract] 
    (x, y) <- [(1, 2), (2, 1)] 
    [f x *** g y] 

我还没有看到一个do块之前,这是一个解决骑士巡逻问题的一部分,在list结束..有人可以解释它是如何工作的?

+3

这段代码等同于'moves = [f x *** g y | (x,y)< - [(+),减去],g < - [(+),减去],' – 2014-10-30 17:39:58

+1

在列表monad中, [x] =返回x'。 – chaosmasttter 2014-10-30 18:38:12

回答

6

你必须解除符号。首先开始写下类型:

import Control.Arrow 

moves :: [(Integer, Integer) -> (Integer, Integer)] 
moves = do 
    f <- [(+), subtract] 
    g <- [(+), subtract] 
    (x, y) <- [(1, 2), (2, 1)] 
    [f x *** g y] 

所以我们在[](名单)单子。

查找Monad []定义:

instance Monad [] where 
    m >>= k    = foldr ((++) . k) [] m 
    m >> k    = foldr ((++) . (\ _ -> k)) [] m 
    return x   = [x] 

并翻译做记号结合并返回:在他们的定义而言

moves = 
    [(+), subtract] >>= \f -> 
    [(+), subtract] >>= \g -> 
    [(1, 2), (2, 1)] >>= \(x,y) -> 
    [f x *** g y] 

然后,终于,改写结合:

return上榜

定义>> =的>> =的>>

moves = 
    foldr ((++) . (\f -> 
     foldr ((++) . (\g -> 
       [(1, 2), (2, 1)] >>= \(x,y) -> 
       return (f x *** g y)) 
       ) [] [(+), subtract] 
      )) [] [(+), subtract] 

定义=

moves = 
    foldr ((++) . (\f -> 

      [(+), subtract] >>= \g -> 
      [(1, 2), (2, 1)] >>= \(x,y) -> 
      return (f x *** g y) 

      )) [] [(+), subtract] 

定义

moves = 
    foldr ((++) . (\f -> 
     foldr ((++) . (\g -> 
      foldr ((++) . (\(x,y) -> return (f x *** g y)) 
        ) [] [(1, 2), (2, 1)] 
       )) [] [(+), subtract] 
      )) [] [(+), subtract] 

撤消返回:

moves = 
    foldr ((++) . (\f -> 
     foldr ((++) . (\g -> 
      foldr ((++) . (\(x,y) -> [f x *** g y]) 
        ) [] [(1, 2), (2, 1)] 
       )) [] [(+), subtract] 
      )) [] [(+), subtract] 

所以你看到它在两个元素列表上的嵌套。 展开折叠留给读者练习:)

+5

我已经知道单子表达式理解中发生了什么,但是我发现'foldr'的desugared版本不可能遵循。我不知道它应该如何帮助那些不知道发生了什么的人。 – amalloy 2014-10-30 18:45:42

+1

我不希望初学者理解'(++)。 (\ f - > ...)',要么。最好的情况是,会出现这样的问题:“为什么这不会触发类型错误?”。 – chi 2014-10-30 19:29:40

+2

如果你使用'concatMap f'而不是'foldr((++)。f)[]' – 2014-10-30 22:58:33