Functions

4.1 Defining and Calling Functions

Function application binds tightest: f x + 1 means (f x) + 1.

square :: Int -> Int
square x = x * x

add :: Int -> Int -> Int
add x y = x + y

main :: IO ()
main = do
  print (square 5)          -- 25: function application is just a space
  print (add 2 3)           -- 5
  print (add 2 (square 3))  -- 11: parentheses group arguments
  print (square $ add 1 2)  -- 9: $ is low-precedence application

4.2 Currying and Partial Application

-- add :: Int -> Int -> Int   really means   add :: Int -> (Int -> Int)
addFive :: Int -> Int
addFive = add 5            -- partial application returns a new function

doubleAll :: [Int] -> [Int]
doubleAll = map (* 2)      -- operator section

-- Sections
(+ 1) 5        -- 6
(2 ^) 10       -- 1024 (2 ^ 10)
(^ 2) 10       -- 100  (10 ^ 2)
(`div` 2) 9    -- 4
subtract 1 10  -- 9 (note: (- 1) is the number -1, not a section)

4.3 Operators as Functions and Functions as Operators

(+) 3 4            -- 7: an operator in parentheses is a prefix function
3 `add` 4          -- 7: a function in backticks is an infix operator

infixl 6 |+|       -- declare fixity: infixl/infixr/infix with precedence 0–9
(|+|) :: (Int, Int) -> (Int, Int) -> (Int, Int)
(a, b) |+| (c, d) = (a + c, b + d)

4.4 Lambdas, Composition and Point-Free Style

map (\x -> x * x + 1) [1, 2, 3]      -- [2, 5, 10]: anonymous function
(\x y -> x + y) 3 4                  -- 7

-- Composition: (f . g) x = f (g x)
countWords :: String -> Int
countWords = length . words           -- point-free (no explicit argument)

process :: [Int] -> Int
process = sum . map (* 2) . filter even

-- $ avoids parentheses; & (Data.Function) is reverse application
result1 = sum (map (* 2) (filter even [1 .. 10]))
result2 = sum $ map (* 2) $ filter even [1 .. 10]
result3 = [1 .. 10] & filter even & map (* 2) & sum   -- import Data.Function ((&))

4.5 Conditional Expressions

classify :: Int -> String
classify n = if n < 0 then "negative" else if n == 0 then "zero" else "positive"

describe :: Int -> String
describe n = case compare n 0 of
  LT -> "negative"
  EQ -> "zero"
  GT -> "positive"