Lesson 3 / 25
Expressions, Types and Functions
Write functions with type signatures, guards, where and let, and use operators.
Everything is an expression
A Haskell program is built from expressions and definitions. Basic types include Int (fixed-size), Integer (arbitrary precision), Double, Bool, Char and String (a list of Char; real projects use Text). Write a type signature above each top-level function: withGst :: Int -> Int. A function of several arguments has type Int -> Int -> Int: functions are curried, taking one argument at a time, so partial application (add 5) produces a new function. Application binds tighter than any operator: f x + 1 means (f x) + 1. if then else is an expression and always has an else. Guards (| condition = result) choose between cases and otherwise catches the rest. where defines helper values after a function, and let ... in defines them before an expression. Operators are functions: (+) 2 3, and any function can be used infix with backticks, as in 7 `div` 2. Sections partially apply operators: (* 2), (subtract 1). Numeric literals are polymorphic, and conversions are explicit: fromIntegral converts integers to other numeric types. Integer division uses div and mod; / is for fractional types.
Functions with guards and where
Prices in paise to avoid floating-point rounding.
-- Integer paise avoid floating-point surprises with money
withGstPaise :: Int -> Int
withGstPaise paise = paise + (paise * 18 + 50) `div` 100 -- rounds to the nearest paisa
shippingFee :: Int -> Bool -> Int
shippingFee totalPaise express
| totalPaise >= 100000 = 0
| express = 9900
| otherwise = 4900
bmiCategory :: Double -> Double -> String
bmiCategory weightKg heightM
| bmi < 18.5 = "underweight"
| bmi < 25 = "normal"
| otherwise = "overweight"
where
bmi = weightKg / (heightM * heightM)
average :: [Int] -> Double
average [] = 0
average xs = fromIntegral (sum xs) / fromIntegral (length xs)
addTax :: Int -> Int -> Int
addTax rate amount = amount + amount * rate `div` 100
main :: IO ()
main = do
print (withGstPaise 10000) -- 11800
print (shippingFee 20000 True) -- 9900
putStrLn (bmiCategory 68 1.75) -- normal
print (7 `div` 2, 7 `mod` 2) -- (3,1)
let gst18 = addTax 18 -- partial application
print (map gst18 [100, 250]) -- [118,295]Write the type first
Writing the type signature before the body clarifies what a function should do, gives better error messages, and lets you use typed holes (_) so GHC tells you what type is needed at that spot.
Quick check: What is the type of `addTax 18` if `addTax :: Int -> Int -> Int`?
- Int
- Int -> Int -> Int
- Int -> Int
- It is a type error
Answer
Int -> Int — Curried functions return a new function when partially applied.