Want to see the full-length video right now for free?
 
  Compilers are powerful helpers but they can only do so much with primitives. Joël and Stephanie fix a bug by introducing domain-specific types. Learn about how these encode real-world context, what are the downsides, and how some functional programming concepts can make those downsides go away.
Previously discussed, don't depend too heavily on low-level constructs.
Two Ints can bean different things and easily be confused for each other
type alias User =
  { age : Int
  , salary : Int
  , balance : Int
  }
payday : User -> User
payday user =
  { user | balance = pay user.age user.salary }
pay : Int -> Int -> Int
pay salary age =
  salary + (age * 10)
type Dollar = Dollar Int
type alias User =
  { age : Int
  , salary : Dollar
  , balance : Dollar
  }
payday : User -> User
payday user =
  { user | balance = pay user.age user.salary }
pay : Dollar -> Int -> Int
pay (Dollar salary) age =
  salary + (age * 10)
gives error
The 1st argument to function pay is causing a mismatch.
Function pay is expecting the 1st argument to be:
Dollar
But it is:
Int
Wrapping, doing thing, and re-wrapping usually is the sign of a map function
module Dollar exposing(Dollar, fromInt, map2)
type Dollar = Dollar Int
fromInt : Int -> Dollar
fromInt =
  Dollar
map2 : (Int -> Int -> Int) -> Dollar -> Dollar -> Dollar
map2 f (Dollar d1) (Dollar d2) =
  Dollar <| f d1 d2
payday : User -> User
payday user =
  { user | balance = Dollar.map2 (+) user.balance (pay user.age user.salary) }
With map and map2, we can implement most custom operations
plus : Dollar -> Dollar -> Dollar
plus =
  map2 (+)
minus : Dollar -> Dollar -> Dollar
minus =
  map2 (-)
times : Int -> Dollar -> Dollar
times n =
  map ((*) n)
divideBy : Int -> Dollar -> Dollar
divideBy n =
  map (\d -> d / n)
square : Dollar -> Dollar
square =
  map (\d -> d ^ 2)
Some articles: * Avoiding primitives in Elm * Algebraic blindness
Ideas described here implemented as a package.