Created
March 23, 2016 23:05
-
-
Save laser/4266c0521e1db46c5b83 to your computer and use it in GitHub Desktop.
Transformers Code Sample
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Main where | |
import Control.Applicative (liftA2) | |
import Data.Char (isAlpha) | |
import Data.Either | |
import Data.List (find) | |
data GameError = InvalidInput String | |
| IncorrectGuess deriving (Show, Eq) | |
promptForGuess :: IO (Either GameError String) | |
promptForGuess = do | |
putStrLn "Enter a guess:" | |
guess <- getLine | |
return (validateInput guess) | |
validateInput :: String -> Either GameError String | |
validateInput guess = if (foldr (\item acc -> acc && isAlpha item) True guess) | |
then Right guess | |
else Left (InvalidInput guess) | |
checkGuess :: String -> String -> IO (Either GameError String) | |
checkGuess fileName guess = do | |
contents <- readFile fileName | |
return $ maybe (Left IncorrectGuess) (return) $ find (==guess) (lines contents) | |
printResults :: Either GameError String -> IO () | |
printResults (Left (InvalidInput guess)) = putStrLn $ "\"" ++ guess ++ "\" is not a valid guess." | |
printResults (Left (IncorrectGuess)) = putStrLn $ "Nope. That last guess was wrong." | |
printResults (Right guesses) = putStrLn ("Your two guesses (" ++ guesses ++ ") were correct.") | |
game :: IO (Either GameError String) | |
game = do | |
putStrLn "I have lived in many cities. Can you guess one?" | |
e1 <- promptForGuess | |
case e1 of | |
err@(Left _) -> return err | |
Right g1 -> do | |
r1 <- checkGuess "cities.txt" g1 | |
case e1 of | |
err@(Left _) -> return err | |
Right m1 -> do | |
putStrLn "I like a lot of bands. Can you guess one?" | |
e2 <- promptForGuess | |
case e2 of | |
err@(Left _) -> return err | |
Right g2 -> do | |
r2 <- checkGuess "bands.txt" g2 | |
case r2 of | |
Right m2 -> return $ Right $ m1 ++ " and " ++ m2 | |
err -> return err | |
main :: IO () | |
main = game >>= printResults | |
------------ EitherIO | |
data EitherIO e a = EitherIO { runEitherIO :: IO (Either e a) } | |
instance Functor (EitherIO e) where | |
fmap f = EitherIO . fmap (fmap f) . runEitherIO | |
instance Applicative (EitherIO e) where | |
pure = EitherIO . pure . Right | |
f <*> x = EitherIO $ liftA2 (<*>) (runEitherIO f) (runEitherIO x) | |
instance Monad (EitherIO e) where | |
return = pure | |
x >>= f = EitherIO $ runEitherIO x >>= either (return . Left) (runEitherIO . f) | |
lift' :: IO a -> EitherIO e a | |
lift' x = EitherIO (fmap Right x) | |
bad :: EitherIO String Int | |
bad = EitherIO $ do | |
putStrLn "bad!" | |
return $ Left "bummer" | |
good :: EitherIO String Int | |
good = EitherIO $ do | |
putStrLn "good" | |
return $ Right 100 | |
ex3 = do | |
v1 <- good | |
v2 <- bad -- short-circuit here | |
v3 <- good | |
return (v1, v2) | |
------------ get ya transform on | |
data EitherT e m a = EitherT { runEitherT :: m (Either e a) } | |
instance Functor m => Functor (EitherT e m) where | |
fmap f = EitherT . fmap (fmap f) . runEitherT | |
instance Applicative m => Applicative (EitherT e m) where | |
pure = EitherT . pure . Right | |
f <*> x = EitherT $ liftA2 (<*>) (runEitherT f) (runEitherT x) | |
instance Monad m => Monad (EitherT e m) where | |
return = EitherT . return . Right | |
x >>= f = EitherT $ runEitherT x >>= either (return . Left) (runEitherT . f) | |
lift :: Functor m => m a -> EitherT e m a | |
lift x = EitherT (fmap Right x) | |
game' :: IO (Either GameError String) | |
game' = runEitherT $ do | |
lift $ putStrLn "I have lived in many cities. Can you guess one?" | |
g1 <- EitherT promptForGuess | |
m1 <- EitherT $ checkGuess "cities.txt" g1 | |
lift $ putStrLn "I like a lot of bands. Can you guess one?" | |
g2 <- EitherT promptForGuess | |
m2 <- EitherT $ checkGuess "bands.txt" g2 | |
return (m1 ++ " and " ++ m2) | |
main' :: IO () | |
main' = game' >>= printResults |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment