Here are some example variations of Main.hs which fail to compile, demonstrating that this technique is helping the program be more correct:
This version of main fails to compile simply because I haven't named the numeratorInt.
import Div
import Nonzero
import Text.Read
import Named
main = do
numeratorString <- getLine
denominatorString <- getLine
case (,) <$> readMaybe numeratorString <*> readMaybe denominatorString :: Maybe (Double, Double) of
Nothing -> error "Both must be valid numbers."
Just (numeratorInt, Name denominatorInt) ->
case checkNonzero denominatorInt of
Nothing -> error "Denominator must be non-zero."
Just denominatorNonZero ->
let result = divide denominatorNonZero numeratorInt denominatorInt
in putStrLn ("Result: " ++ show result)
Couldn't match expected type ‘Named x0 Double’ with actual type ‘Double’
Here is a version where I got the arguments to divide the wrong way round:
import Div
import Nonzero
import Text.Read
import Named
main = do
numeratorString <- getLine
denominatorString <- getLine
case (,) <$> readMaybe numeratorString <*> readMaybe denominatorString :: Maybe (Double, Double) of
Nothing -> error "Both must be valid numbers."
Just (Name numeratorInt, Name denominatorInt) ->
case checkNonzero denominatorInt of
Nothing -> error "Denominator must be non-zero."
Just denominatorNonZero ->
let result = divide denominatorNonZero denominatorInt numeratorInt
in putStrLn ("Result: " ++ show result)
• Couldn't match type ‘n’ with ‘n1’
The denominatorNonZero
proof refers to denominatorInt
by a
generate name type (n1
), and numeratorInt
's name (n
) is
different.