2016-11-20 50 views
0

你好人的StackOverflow!concatMap解釋

我已經開始與Haskell合作了,並且偶然發現了concatMap函數。 因爲我很新的這門語言,我有一些問題的理解下面的代碼(source):

concatMap f = cmap where 
    cmap [] = [] 
    cmap (x : xs) = accum (f x) where 
     accum [] = cmap xs 
     accum (y : ys) = y : accum ys 

據我瞭解功能concatMap發生在一個參數f這是一個功能。

但是我們如何設置一個函數等於另一個?我們是否將f的結果設置爲cmap,或者我們是否使用cmap作爲f的參數?

任何幫助將不勝感激,

預先感謝您!

+3

這段代碼是寫成point-free-ish的,這對初學者不是很友好。在'='的兩邊添加'ys',它可能會變得更容易,例如'concatMap f ys = cmap ys'。此外,'concatMap f'的規範定義是'concat。地圖f'。 – Zeta

+2

我可能會進一步說,代碼很混亂。我沒有看到有什麼好的理由來編寫奇怪的'accum'函數,而不是使用'cmap(x:xs)= f x ++ cmap xs'。 – dfeuer

回答

4

您發佈的代碼對於初學者來說並不容易。幸運的是,我們可以通過一塊重寫片:

accum [] = cmap xs 
accum (y : ys) = y : accum ys 

上面的功能,當輸入列表爲空返回cmap xs,否則就y:ys發射y作爲第一輸出元件,然後前進到輸出accum xs,遞歸。

因此,accum zs將簡單地輸出zs中的所有元素,然後在此之後繼續使用cmap xs。我們可以將其重寫爲:

accum zs = zs ++ cmap xs 

其中++是列表級聯。

然後我們就可以重寫整個代碼如下,因此:

concatMap f = cmap where 
    cmap [] = [] 
    cmap (x : xs) = f x ++ cmap xs 

我們可以進一步改寫是

concatMap f [] = [] 
concatMap f (x : xs) = f x ++ concatMap f xs 

這應該是對於初學者更容易。更多非正式上述定義滿足等式:

concatMap f [x1,x2,...,xn] = 
    f x1 ++ f x2 ++ ... ++ f xn ++ [] 

所以,我們可以看到什麼呢concatMap。它將f應用於每個列表元素,並且對於每個列表元素f都必須返回一個列表。然後,將所有這些列表連接起來。

例如:

concatMap (\x -> [1..x]) [3,1,2] = 
    [1,2,3] ++ [1] ++ [1,2] = 
    [1,2,3,1,1,2] 
+0

非常感謝您的快速,但非常詳細的答案@chi 我已經標記爲答案。 – TheCoolFrood

3

綺的回答涵蓋了如何concatMap的作品,所以我會特別關注你的疑惑之一:

但我們如何設置另一個相等的功能?

Haskell中的函數是一個值,就像任何其他值一樣。

GHCi> foo = "foo" 

這是foo的定義,這恰好是一個字符串:

GHCi> :t foo 
foo :: [Char] 
GHCi> putStrLn foo 
foo 

以同樣的方式...

GHCi> add = (+) 

...這是一個定義add,這恰好是一個功能:

GHCi> :t add 
add :: Num a => a -> a -> a 
GHCi> add 2 3 
5 

在上面的定義中,爲了強調我只是定義了一個值,我沒有明確寫出add的任何一個參數。這是完全沒有做到這一點,雖然:

GHCi> add x y = (+) x y 

(需要注意的是x + y,這是怎麼我們通常會寫上述定義的右手邊,是(+) x y簡單方便的替代語法)

寫的定義不同的方式利用部分應用程序的只提第一個參數:

GHCi> add x = (+) x 

我們也可以,只是爲它(並可能澄清是怎麼回事),移動(+) x在一個WHERE子句單獨定義的緣故......

GHCi> :{ 
GHCi| add x = plusX 
GHCi|  where 
GHCi|  plusX = (+) x 
GHCi| :} 

...並再次明確寫入第二個參數:

GHCi> :{ 
GHCi| add x = plusX 
GHCi|  where 
GHCi|  plusX y = (+) x y 
GHCi| :} 

plusX是一個函數,它接受一個參數並將其添加到xadd是一個函數,它接受一個參數x,並返回與該x對應的plusX函數。當我們做add 2 3(順便說一下,它相當於(add 2) 3),這是第二個函數,它將第二個參數作爲add

現在,比較上面的concatMap定義:

concatMap f = cmap where 
    cmap [] = [] 
    cmap (x : xs) = accum (f x) where 
     accum [] = cmap xs 
     accum (y : ys) = y : accum ys 

的定義以類似的方式佈置。 cmap是一個函數,它獲取一個列表並使用f(參數concatMap)生成一個結果,與plusX使用的參數add非常相似。

所以,總結一下:

難道我們設置f大於CMAP的結果,還是我們使用CMAP使用F參數?

都沒有。我們使用f來定義cmap,然後用它來定義concatMap作爲一個整體。

+0

謝謝你的回答@duplode。 我不得不在chi和你的答案之間選擇標記爲「答案」。對我而言,我需要你和你的答案來充分理解發生了什麼。但是我標記了Chi的答案,因爲它給出了concatMap函數的更廣泛的概述,這可能對其他人有用,在這個問題上尋求幫助。 但我很努力,它幫了我很多! – TheCoolFrood

+0

@TheCoolFrood不客氣,我很高興它有幫助。 – duplode