Tidy up the maths, copy some ideas from the Haskell version