6

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

2
  • +1 for forcing me to overcome my complete lack of focus and think about Haskell, which I haven't looked at in months. Hope I can focus some more and refine my answer into something more useful. Commented Feb 22, 2011 at 1:14
  • As a rule of thumb: If you want to get rid of a (on both sides) trailing argument, replace all top level $ by . (this works only in "simple" cases) Commented Feb 22, 2011 at 8:04

3 Answers 3

10

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

Sign up to request clarification or add additional context in comments.

6 Comments

Yes, all that is correct. Unless you consider "with type" :: to be an operator, which has lower precedence than ($).
@luqui - Yeah, I was verifying this myself. Good to know about :: though. It would make sense for it to be the lowest precedence. Is it considered an operator?
@Chris, technically no; it has a special place in the grammar.
I was actually trying duplicate the (!!) operator without using written arguments. I am a haskell newb and I figured it might be an interesting exercise. This version fails to throw exceptions if you try something like f 20 [1..10] though, so it's definitely incorrect as written.
@chuck taylor - Ah. I was wondering why you'd try to duplicate it. I'd use pattern matching personally. And I don't think it's very nice to say it's "definitely incorrect as written" since you didn't specify any requirements. If you're trying to reimplement built-in behavior, you should say so off the bat. Otherwise you'll get a lot of answers (like mine) telling you not to do that.
|
6

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]

Comments

5
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

1 Comment

I don't think you have enough .s there.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.