2014-08-31 63 views
6

我想編寫一個Haskell函數,它返回一個附加到自身計數時間的列表(如Python中的lst * count)。Pointfree版本不能編譯,但有意義的版本呢?

我第一次嘗試是:

self_append_n :: Int -> [a] -> [a] 
self_append_n = concat . replicate 

我的理由是,replicate接受計數和價值,併產生值的列表。當該值本身是一個列表時,剩下的就是將這些列表連接在一起。然而,這給出了一個令人困惑的錯誤:

Couldn't match type `[a0]' with `[a] -> [a]' 
Expected type: [[a0]] -> [a] -> [a] 
    Actual type: [[a0]] -> [a0] 
In the first argument of `(.)', namely `concat' 
In the expression: concat . replicate 
In an equation for `self_append_n': 
    self_append_n = concat . replicate 

然後我寫了一個貼題版本:

self_append_n a b = concat $ replicate a b 

和它的作品!

爲什麼免費版本無法編譯,但添加點使其工作?

回答

11

這可能有助於明確parenthesise簽名:

selfAppend :: Int -> ([a]   -> [a]) 
replicate :: Int -> ([a]->[[a]]) 
concat  ::   [[a]]  -> [a] 

如果您嘗試撰寫concat . replicate,你最終給concat部分appied結果replicate,即[a] -> [[a]]。這不符合[[a]]

您需要做的是在交付結果之前首先通過兩個參數到replicate。 IMO做到這一點最好的辦法就是 「半pointfree」:

selfAppend n = concat . replicate n 

的可讀性替代將是

selfAppend' = curry $ concat . uncurry replicate 
selfAppend'' = (concat.) . replicate 

或者與臭名昭著操作

(.:) :: (c->d) -> (a->b->c) -> a->b->d 
(.:) = (.).(.) 
-- `≡ fmap fmap fmap`, also a popular implementation... 

可以簡單的寫

selfAppend''' = concat .: replicate 
+4

我明白了。組合失敗,因爲複製的實際返回類型不是列表,而是函數(它本身返回一個列表)。 – 2014-08-31 21:05:18

+1

是的。不幸的是,Haskell的_curry everything_哲學並不總是一種好處(儘管通常是這樣)。 – leftaroundabout 2014-08-31 21:09:09