[英]Haskell: Calculate the length of a list using (curry snd)
I was given an assignment to calculate the length of a list using the foldr
Haskell function, so I did these two examples我得到了一个使用
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
Then, as a personal challenge, the professor asked us to use the snd
function and yesterday I came up with this:然后,作为个人挑战,教授要求我们使用
snd
函数,昨天我想出了这个:
flength'' :: [a] -> Int
flength'' = foldr ((+1).(curry snd)) 0
What I want to happen is that this function will turn the head of the list h
and the accumulator 0
into the pair (h,0)
then return 0
and after that apply it to the function (+1)
我想要发生的是这个函数将把列表的头部
h
和累加器0
变成对(h,0)
然后返回0
然后将它应用到函数(+1)
I expected this to be done recursively, effectively giving me the length of the list at the end.我希望这是递归完成的,最后有效地给了我列表的长度。
Instead, I get this error message:相反,我收到此错误消息:
[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.
Why is this happening and how can I get this code to work?为什么会发生这种情况以及如何使此代码正常工作?
Let us lay all our tools in front of us, like a good artisan does:让我们把所有的工具都摆在我们面前,就像一个好的工匠一样:
foldr :: (a -> b -> b) -> b -> [a] -> b
snd :: (a, b) -> b
First, we note that snd
and foldr
do not really fit well.首先,我们注意到
snd
和foldr
不太适合。 So let's use curry
, just like you did, and add curry snd
to our small tool library:因此,让我们像您一样使用
curry
,并将curry snd
添加到我们的小型工具库中:
foldr :: (a -> b -> b) -> b -> [a] -> b
curry snd :: a -> b -> b
This looks very promising.这看起来很有希望。 Now we need to add
1
to the result of curry snd
, otherwise we're just writing flip const
.现在我们需要将
curry snd
的结果加1
,否则我们只是在写flip const
。 Let's start with a lambda:让我们从一个 lambda 开始:
\a b -> 1 + curry snd a b
= \a b -> ((+1) . curry snd a) b
We can now shove of b
and end up with我们现在可以推
b
并最终得到
\a -> (+1) . curry snd a
= \a -> (.) (+1) (curry snd a)
= \a -> ((.) (+1)) (curry snd a)
= \a -> (((.) (+1)) . curry snd) a
Now we can eta-reduce a
from both sides too and end up with现在我们也可以从两边对
a
进行 eta-reduce 并最终得到
(((.) (+1)) . curry snd) = ((+1) . ) . curry snd
Therefore, your third variant would be因此,您的第三个变体将是
flength'' = foldr (((+1) . ) . curry snd) 0
Now, why did you get your error message?现在,您为什么会收到错误消息? You were close with
(+1) . curry snd
你很接近
(+1) . curry snd
(+1) . curry snd
, but the types don't work out: (+1) . curry snd
,但类型不工作:
(+1) :: Int -> Int
-- v v
(.) :: (b -> c) -> (a -> b ) -> a -> c
curry snd :: t -> (x -> x)
^ ^
But in your case, the b
s in (.)
's signature didn't match.但是在您的情况下,
(.)
签名中的b
不匹配。 One of them was an Int
, the other was a function.其中一个是
Int
,另一个是函数。
TL;DR : If you want to write f (gxy)
point-free, write ((f.) . g)
TL;DR : 如果你想写
f (gxy)
point-free,写((f.) . g)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.