Skip to content

Instantly share code, notes, and snippets.

@Decoherence
Last active August 29, 2015 14:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Decoherence/d097e787deeb15db36e0 to your computer and use it in GitHub Desktop.
Save Decoherence/d097e787deeb15db36e0 to your computer and use it in GitHub Desktop.
Example: Type-safe rocket launch using the Either monad transformer.
module Main where
import Control.Monad.Trans
import Control.Monad.Trans.Either
import Safe
data Sensor = Temp
| Fuel
| Pressure
deriving Show
data Continue = Success Sensor
deriving Show
data Abort = Failure Sensor
deriving Show
type Value = Integer
type Range = (Value, Value)
-- | Return True if value within range
inRange :: Value -> Range -> Bool
inRange val (a, b)
| val >= a && val <= b = True
| otherwise = False
-- | Read sensor value and either Abort or Continue
check :: Sensor -> Range -> EitherT Abort IO Continue
check sensor (a,b) = do
lift $ putStrLn (show sensor ++ ": ")
val <- lift $ fmap (readNote "Expected numerical input.") getLine
if inRange val (a,b)
then right $ Success sensor
else left $ Failure sensor
-- | Perform all pre-flight checks in sequence, Abort immediately on Failure
goForLaunch :: IO (Either Abort Continue)
goForLaunch = runEitherT $
check Fuel (100,200)
>> check Temp (30,100)
>> check Pressure (10,50)
-- | The main entry point.
main :: IO ()
main = do
putStrLn "Beginning pre-launch checks..."
go <- goForLaunch
case go of
Left err -> do
print err
putStrLn "!! ABORT LAUNCH !!"
Right _ -> do
putStrLn "All systems go."
putStrLn "Lift off!"
{-
OUTPUT:
Beginning pre-launch checks...
Fuel:
150
Temp:
45
Pressure:
40
All systems go.
Lift off!
-}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment