简体   繁体   English

Haskell:使用(curry snd)计算列表的长度

[英]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.首先,我们注意到sndfoldr不太适合。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM