简体   繁体   中英

haskell function declaration

I have been playing around with haskell and I found out that if I write the following function in a code file:

f :: Int -> [a] -> a
f idx str = last $ (take . succ) idx str

then this works totally fine. Naturally, I figured the code would look better without the arguments.

f :: Int -> [a] -> a
f = last $ (take . succ)

But this generates an error when I try to load it into gchi

Couldn't match expected type `[a]'
       against inferred type `Int -> [a1] -> [a1]'
In the second argument of `($)', namely `(take . succ)'
In the expression: last $ (take . succ)
In the definition of `f': f = last $ (take . succ)

Failed, modules loaded: none.

I'm kind of confused about how this could be happening...

You're misunderstanding the precedence. This:

f idx str = last $ (take . succ) idx str

Is parsed like this:

f idx str = last $ ( (take . succ) idx str )

Not (as you think) like this:

f idx str = ( last $ (take . succ) ) idx str

$ has extremely the lowest precedence of any operator, and function calling has extremely the highest. . has the second highest, so (take . succ) binds to it's arguments ( idx str ) before it binds to last $ .

Furthermore, the function (as it compiles) doesn't do what it looks like you want it to do. It increments idx , then takes that character from the string. If that's what you want, why use succ when (+1) works? You've already restricted the type to integers.

As written, your function is identical to the !! operator - it's just an array index function. Is this what you want? Or do you want to succ the item at the given index? You could accomplish that with the following:

f :: Enum a => Int -> [a] -> a
f idx str = succ $ str !! idx
-- or
f idx str = succ $ (!!) str idx
-- or, only one argument
f idx = succ . (!! idx)

I'm still working on a version with no written arguments. Perhaps it's more important to write working code? ;)

This is what happens when you try to compose last with (take . succ)

:t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c

last :: [t] -> t  ~ (b -> c)  
-- so b ~ [t] and c ~ t   

(take . succ) :: Int -> [t] -> [t]  
-- so a ~ int and b ~ [t] -> [t]  

Type of b is inferred to be [t] from last but it couldn't match against the type of b in (take . succ) which is [t] -> [t]

f idx str = last $ (take . succ) idx str
-- applying definition of ($)
f idx str = last ((take . succ) idx str)
-- adding parentheses for clarity
f idx str = last (((take . succ) idx) str)
-- using definition of (.)
f idx str = (last . (take . succ) idx) str
-- η-conversion
f idx = last . (take . succ) idx
-- infix to prefix notation
f idx = (.) last ((take . succ) idx)
-- ading parentheses for clarity
f idx = ((.) last) ((take . succ) idx)
-- using definition of (.)
f idx = ((.) last . (take . succ)) idx
-- η-conversion
f = (.) last . (take . succ)
-- remove parentheses: (.) is right-associative
f = (.) last . take . succ

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