[英]Haskell: Calculate the length of a list using (curry snd)
我得到了一個使用foldr
Haskell 函數計算列表長度的作業,所以我做了這兩個例子
flength :: [a] -> Int
flength = foldr (\ _ n -> n+1) 0
flength' :: [a] -> Int
flength' l = foldr aux 0 l
where
aux _ n = n+1
然后,作為個人挑戰,教授要求我們使用snd
函數,昨天我想出了這個:
flength'' :: [a] -> Int
flength'' = foldr ((+1).(curry snd)) 0
我想要發生的是這個函數將把列表的頭部h
和累加器0
變成對(h,0)
然后返回0
然后將它應用到函數(+1)
我希望這是遞歸完成的,最后有效地給了我列表的長度。
相反,我收到此錯誤消息:
[1 of 1] Compiling Main ( f1.hs, interpreted )
f1.hs:54:24: error:
* No instance for (Num (Int -> Int))
arising from an operator section
(maybe you haven't applied a function to enough arguments?)
* In the first argument of `(.)', namely `(+ 1)'
In the first argument of `foldr', namely `((+ 1) . (curry snd))'
In the expression: foldr ((+ 1) . (curry snd)) 0 xs
Failed, modules loaded: none.
為什么會發生這種情況以及如何使此代碼正常工作?
讓我們把所有的工具都擺在我們面前,就像一個好的工匠一樣:
foldr :: (a -> b -> b) -> b -> [a] -> b
snd :: (a, b) -> b
首先,我們注意到snd
和foldr
不太適合。 因此,讓我們像您一樣使用curry
,並將curry snd
添加到我們的小型工具庫中:
foldr :: (a -> b -> b) -> b -> [a] -> b
curry snd :: a -> b -> b
這看起來很有希望。 現在我們需要將curry snd
的結果加1
,否則我們只是在寫flip const
。 讓我們從一個 lambda 開始:
\a b -> 1 + curry snd a b
= \a b -> ((+1) . curry snd a) b
我們現在可以推b
並最終得到
\a -> (+1) . curry snd a
= \a -> (.) (+1) (curry snd a)
= \a -> ((.) (+1)) (curry snd a)
= \a -> (((.) (+1)) . curry snd) a
現在我們也可以從兩邊對a
進行 eta-reduce 並最終得到
(((.) (+1)) . curry snd) = ((+1) . ) . curry snd
因此,您的第三個變體將是
flength'' = foldr (((+1) . ) . curry snd) 0
現在,您為什么會收到錯誤消息? 你很接近(+1) . curry snd
(+1) . curry snd
,但類型不工作:
(+1) :: Int -> Int
-- v v
(.) :: (b -> c) -> (a -> b ) -> a -> c
curry snd :: t -> (x -> x)
^ ^
但是在您的情況下, (.)
簽名中的b
不匹配。 其中一個是Int
,另一個是函數。
TL;DR : 如果你想寫f (gxy)
point-free,寫((f.) . g)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.