Equational reasoning
haskellforall.com
haskellforall.com
In Haskell, when you see a single equals sign it means that
the left-hand and right-hand side are substitutable for each
other both ways. For example, if you see:
x = 5
That means that wherever you see an x in your program, you
can substitute it with a 5, and, vice versa, anywhere you
see a 5 in your program you can substitute it with an x.
This is missing a key term: "in scope."Apart from that, I'm going to re-read this several times. Thank you.
True, of course.
Sometimes I wish Haskell would have made shadowing variables into a compile error. Shadowing is the number one reason that substitution doesn't always work like you expect. (everyone please use -Wall)
However, substitution also doesn't work sometimes because the types aren't polymorphic enough. Let bindings are monomorphic by default nowadays which can give some surprising results.
It would be cleaner/safer if the language had a keyword like 'shadowlet'.
x <- m1;
f x;
x <- m 2;
f x;
in a do-block, and it's not clear to me how to write 'shadowfrom' (or however you pronounce '<-' in that context). x! <- m 2
Sort of like a strictness annotation. In think it would be a compatible language change, since only identifiers can currently appear left of a <- f1 = let x = 1 in x
f2 = let x = 2 in x
It would be insane to ban that in the name of "equational reasoning". mapM :: Monad m => (a -> m b) -> [a] -> m [b]
it returns the result of the computation. But sometimes you want to iterate over a list but discard the result (say you're printing elements.) mapM_ discards the result: mapM_ :: Monad m => (a -> m b) -> [a] -> m ()
where () denotes a kind of "null type".So if you want to store the results in a new list, you use mapM, but if you don't, and just want the "effects", you use mapM_.
Here's an example of each, using the IO monad. If I have a list of numbers, and I want to iterate through each one and prompt the user for a multiplier, I would write the code like this:
main = do
let numbers = [1.. 10]
numbers' <- forM numbers $ \n -> do
putStrLn "Enter a multiplier"
a <- getLine
return $ n * (read a :: Int)
where forM is just mapM with the arguments reversed to look more like a for-loop. Here I want the results of the computation, so I use forM. If, however I want to just print the numbers out, I'd use forM_ main = do
let numbers = [1.. 10]
forM_ numbers $ \n -> do
putStrLn (show n)The point is to make the (side-)effects happen (since non-strictness means the effects have to be forced, by calling `(>>=)` or similar) but not use the return value (which is how computations are usually forced in Haskell)
And also, the effects happen in the order determined by the function forM_ or whoever, instead of in a hard-to-impossible-to-predict order of the pure non-monadic/non-effect computations defined by equations of function applications.
(The M in fooM is for Monad, indicating that bind (f <<= x) is used instead of simple function application (f x) that is used in the "cousin" function foo. But that is just naming convention.)