Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

haskell function declaration

Tags:

haskell

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...

like image 723
chuck taylor Avatar asked Feb 22 '11 01:02

chuck taylor


3 Answers

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? ;)

like image 83
Chris Lutz Avatar answered Oct 07 '22 12:10

Chris Lutz


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]

like image 37
kefeizhou Avatar answered Oct 07 '22 13:10

kefeizhou


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
like image 36
ephemient Avatar answered Oct 07 '22 14:10

ephemient