2014-10-30 41 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