我試圖瞭解這個優雅的解決方案我自己,所以我試圖推導出類型和評價自己。所以,我們需要編寫一個函數:
zip xs ys = foldr step done xs ys
在這裏我們需要得到step
和done
,不管他們是。召回foldr
的類型,實例化列表:
foldr :: (a -> state -> state) -> state -> [a] -> state
但是我們foldr
調用必須被實例類似下面的,因爲我們必須接受不是一個,而是兩個列表參數:
foldr :: (a -> ? -> ?) -> ? -> [a] -> [b] -> [(a,b)]
因爲->
爲right-associative,這相當於:
foldr :: (a -> ? -> ?) -> ? -> [a] -> ([b] -> [(a,b)])
我們([b] -> [(a,b)])
科爾esponds在原有foldr
類型簽名state
類型的變量,因此我們必須同時更換的state
每次發生:
foldr :: (a -> ([b] -> [(a,b)]) -> ([b] -> [(a,b)]))
-> ([b] -> [(a,b)])
-> [a]
-> ([b] -> [(a,b)])
這意味着,我們通過foldr
參數必須有以下幾種類型:
step :: a -> ([b] -> [(a,b)]) -> [b] -> [(a,b)]
done :: [b] -> [(a,b)]
xs :: [a]
ys :: [b]
回想一下,foldr (+) 0 [1,2,3]
擴展爲:
1 + (2 + (3 + 0))
因此,如果xs = [1,2,3]
和ys = [4,5,6,7]
,我們foldr
調用將擴展爲:
1 `step` (2 `step` (3 `step` done)) $ [4,5,6,7]
這意味着我們的1 `step` (2 `step` (3 `step` done))
結構必須創建一個遞歸函數,將經過[4,5,6,7]
並拉上的元素。 (請記住,如果其中一個原始列表更長,超出的值將被丟棄)。 IOW,我們的結構必須具有[b] -> [(a,b)]
的類型。
3 `step` done
是我們的基本情況,其中done
是初始值,如0
在foldr (+) 0 [1..3]
中。我們不想在3之後壓縮任何東西,因爲3是xs
的最終值,所以我們必須終止遞歸。如何在基本情況下終止列表中的遞歸?您返回空列表[]
。回想起done
類型簽名:
done :: [b] -> [(a,b)]
因此,我們不能只返回[]
,我們必須返回會忽略任何它接收的功能。因此使用const
:
done = const [] -- this is equivalent to done = \_ -> []
現在讓我們開始搞清楚step
應該是什麼。它將a
類型的值與[b] -> [(a,b)]
類型的函數組合在一起,並返回[b] -> [(a,b)]
類型的函數。
在3 `step` done
,我們知道結果值,後來去我們的壓縮列表必須(3,6)
(由原來的xs
和ys
知道)。因此3 `step` done
必須評估爲:
\(y:ys) -> (3,y) : done ys
記住,我們必須返回一個功能,這裏面我們莫名其妙地拉上拉鍊元素,上面的代碼是情理之中的事情和typechecks。
現在我們假設step
應該如何評估,讓我們繼續評估。下面是我們的foldr
評估所有減少步驟看起來怎麼樣:
3 `step` done -- becomes
(\(y:ys) -> (3,y) : done ys)
2 `step` (\(y:ys) -> (3,y) : done ys) -- becomes
(\(y:ys) -> (2,y) : (\(y:ys) -> (3,y) : done ys) ys)
1 `step` (\(y:ys) -> (2,y) : (\(y:ys) -> (3,y) : done ys) ys) -- becomes
(\(y:ys) -> (1,y) : (\(y:ys) -> (2,y) : (\(y:ys) -> (3,y) : done ys) ys) ys)
評價產生了這個實施步驟(注意,我們佔ys
用完元素的早就被返回一個空列表):
step x f = \[] -> []
step x f = \(y:ys) -> (x,y) : f ys
因此,全功能zip
被實現如下:
zip :: [a] -> [b] -> [(a,b)]
zip xs ys = foldr step done xs ys
where done = const []
step x f [] = []
step x f (y:ys) = (x,y) : f ys
PS:我如果你受到褶皺優雅的啓發,請閱讀Writing foldl using foldr,然後閱讀Graham Hutton的文章A tutorial on the universality and expressiveness of fold。
這是如何工作的?不折疊只需要3個參數? – Claudiu 2008-10-24 20:51:46