简体   繁体   中英

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

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:

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)

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. So let's use curry , just like you did, and add curry snd to our small tool library:

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 . Let's start with a 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

\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

(((.) (+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 , but the types don't work out:

(+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. One of them was an Int , the other was a function.

TL;DR : If you want to write f (gxy) point-free, write ((f.) . g)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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