1
 let f = map tail.lines
 f "fsdaf\nfdsf\n"

why it work?

let f = map tail.tail.lines
f "fasdf\nfasdfdsfd\n"

I get result:

["asdfdsfd"]
let f = map (tail.tail).lines
f "fasdf\nfasdfdsfd\n"

I get result:

["sdf","sdfdsfd"]

I want to know haskell how to parse the code above.

2 Answers 2

6

Lets look at your first example:

let f = map tail.tail.lines
f "fasdf\nfasdfdsfd\n"

Firstly, lines breaks your input string into an array of strings: ["fasdf","fasdfdsfd"].

Now, working right to left, tail drops the "head" of the list: ["fasdfdsfd"]

Lastly, map tail applies the "tail" to each element in the list: ["asdfdsfd"]

Your second example works similarly:

let f = map (tail.tail).lines
f "fasdf\nfasdfdsfd\n"

Again, you break the input string into an array of strings: ["fasdf","fasdfdsfd"]

Now however, you're creating a composite function (tail.tail) (drop the "head" of the list, twice), and mapping it to each element in the list.

Therefore you drop the first two characters of each string.

["sdf","sdfdsfd"]

Both your examples are working as intended. Have a read about associativity and composite functions in haskell to understand more about it.

Edit: the difference is essentially this:

map tail (tail lines) vs map (tail.tail) lines

Remember that in Haskell, functions are first class citizens - you can create composite functions (example: (+1).(+1)) and do other operations (such as map a function to a list) that are not common in other languages.

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

4 Comments

One of the first hurdles I had to overcome learning Haskell is to see spaces as very tight bindings. Taken in the context of a natural language where space is a word separator, it appears to be doing map (tail.tail.lines) (since there's no space between the function composition, it must be bound more tightly, right?) but of course that's not true at all in Haskell.
I'm sorry, i still do not understand why the two output differents, I want to know the way haskell parse code.
Thanks for your help. China has an old saying: 醍醐灌顶
(((map tail) tail) lines) is ill typed.
1

The first post is exactly correct, however since you seam to have more questions, here is my attempt...

When you try to understand what this code does, it is important to understand what the functions do and in what order they are applied, so lets have a look:

lines :: String -> [String] --takes a String and returns a list of Strings
tail :: [a] -> [a] --takes a (nonempty) list and drops the head (a list containing the rest)
(.) :: (b -> c) -> (a -> b) -> a -> c --function composition

now this is important... Function composition is right associative and has a precedence of 9 (the highest!)

map :: (a -> b) -> [a] -> [b] --applies (a -> b) to every element of [a]

now to your code:

let f = map tail.tail.lines

is equivalent to

let f x = map tail ((tail.lines) $ x)

this means that you will map tail over the result of the tail of the result of lines. This behavior is because (.), as well as function application is right associative in Haskell. It is also worth noting, that (tail.lines) is the result of partial function application (as you can see from the type-signature of (.) the a is missing... therefor it will return a function that takes an a and returns a c)

In your later example:

let f = map (tail.tail).lines

the order of application is changed by the parenthesizes... this version is equivalent to:

let f x = map (tail.tail) (lines $ x)

so it will map tail.tail (dropping the head twice) over the result of lines.

The key is understanding associativity. It determines which function gets applied first in the absence of parenthesizes and if the functions have the same precedence.

I hope this helps you to understand the difference.

1 Comment

Minor point: it's not that important that (.) is right associative: even if it were left associative it wouldn't matter.

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.