0

I have read Printing the values inside a tuple in Haskell and the solution works. My intention with this question is understand what does $ symbol by "translating" the code into a $ free code.

showDetails :: (String, Int, Int) -> String
showDetails (name, uid, _) = "Your name is:" ++ name ++ " Your ID is: " ++ show uid

main = do 
    putStrLn . unlines . map showDetails $ [("A",100,1),("B",101,2)]

How does $ to tell showDetails to be applyed to list elements (the tuples)? What is the $ free version of that line?

schuelermine
  • 1,958
  • 2
  • 17
  • 31
Nestoter
  • 79
  • 9
  • The suggested duplicate -- while not a perfect match in title -- does cover this case and suggests `(putStrLn . unlines . map showDetails) [("A",100,1),("B",101,2)]` – that other guy May 08 '19 at 18:23

1 Answers1

5

$ is just function application:

f $ x = f x

Put like that, it looks useless. But it actually has a number of uses - and one of the most common ones comes from the fact that, as an infix operator, it has a lower precedence than any other. That is, when parsing the expression, Haskell takes everything to its left (that doesn't include another $) and everything to its right (likewise), and effectively puts both sides in parentheses.

This allows one to use $ as a substitute for parentheses, since f $ complicatedExpression is the same as f (complicatedExpression). So in your example:

putStrLn . unlines . map showDetails $ [("A",100,1),("B",101,2)]

is identical to

(putStrLn . unlines . map showDetails) ([("A",100,1),("B",101,2)])

and the choice is purely stylistic preference. But most prefer $, particularly because multiple $s are much nicer than multiply-nested parentheses.

Robin Zigmond
  • 17,805
  • 2
  • 23
  • 34
  • Hey Robin, and how ```(putStrLn . unlines . map showDetails) ([("A",100,1),("B",101,2)])``` does actually work? Why ```putStrLn . unlines . (map showDetails [("A",100,1),("B",101,2)])``` it's not the correct answer? I think ghci should resolve the map sD [] before everything else. – Nestoter May 08 '19 at 18:51
  • @Nestoter `putStrLn . unlines . (map showDetails [("A",100,1),("B",101,2)])` is a type error, because `.` expects a function type on either side, and `map showDetails [("A",100,1),("B",101,2)]` is not a function but a list of strings. In the correctly grouped version, you compose 3 functions to form another function - whose type is `[(String, Int, Int)] -> IO ()` - and apply it to a specific list of triples. – Robin Zigmond May 08 '19 at 19:03
  • I should add that `(putStrLn . unlines) (map showDetails [("A",100,1),("B",101,2)])` is fine. As is `putStrLn ((unlines . map showDetails) [("A",100,1),("B",101,2)])` - although I think that last version is clearly inferior to the others, due to additional nesting. But there are lots of ways of expressing the same thing. – Robin Zigmond May 08 '19 at 19:12
  • Awesome, thanks Robin. – Nestoter May 09 '19 at 00:00