I have been pl开发者_StackOverflowaying 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
精彩评论