Last active
May 14, 2019 12:47
-
-
Save radix/a47b91370e369b047387 to your computer and use it in GitHub Desktop.
Final haskell example for my STL talk
This file contains 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
{-# LANGUAGE GADTs #-} | |
{-# LANGUAGE StandaloneDeriving #-} | |
{-# LANGUAGE ViewPatterns #-} | |
import Text.Show.Functions | |
import Control.Monad.Operational | |
-- Core effect definition | |
data Intent result where | |
Prompt :: String -> Intent String | |
Display :: String -> Intent () | |
deriving instance Show (Intent result) | |
type MyEffect a = Program Intent a | |
prompt p = singleton (Prompt p) | |
display o = singleton (Display o) | |
-- |run programs in the real world | |
runIO :: MyEffect a -> IO a | |
runIO (view -> (Return x)) = return x | |
runIO (view -> (Prompt p :>>= cont)) = do | |
putStr p | |
line <- getLine | |
runIO (cont line) | |
runIO (view -> (Display o :>>= cont)) = do putStrLn o; runIO (cont ()) | |
-- |A sample program | |
greet :: MyEffect (String, String) | |
greet = do | |
name <- prompt "Enter your name> " | |
display ("Hello there, " ++ name ++ "!") | |
fname <- prompt "Friend's name? " | |
display ("Greets, " ++ fname ++ ".") | |
return (name, fname) | |
-- Testing API | |
-- |Check if the next instruction is a Prompt with the given parameter, | |
-- and simulate returning a value. | |
checkPrompt :: String -> String -> MyEffect a -> Either String (MyEffect a) | |
checkPrompt expected response prog = | |
case view prog of | |
(Prompt p :>>= cont) | |
| p == expected -> Right (cont response) | |
(intent :>>= cont) -> Left $ "Expected (Prompt " ++ show expected ++ ") Got (" ++ show intent ++ ")" | |
-- |Check if the next instruction is a Display with the given parameter | |
checkDisplay :: String -> MyEffect a -> Either String (MyEffect a) | |
checkDisplay expected prog = | |
case view prog of | |
(Display o :>>= cont) | |
| o == expected -> Right (cont ()) | |
(intent :>>= cont) -> Left $ "Expected (Display " ++ show expected ++ ") Got (" ++ show intent ++ ")" | |
-- |Check if the next instruction is a Return with the given parameter | |
checkReturn :: (Eq a, Show a) => a -> MyEffect a -> Either String () | |
checkReturn expected prog = | |
case view prog of | |
Return x | x == expected -> Right () | |
| otherwise -> Left $ "Expected (Return " ++ show expected ++ ") Got (Return " ++ show x ++ ")" | |
-- Finally, the test case for the `greet` program. | |
testGreet prog = | |
Right prog >>= | |
checkPrompt "Enter your name> " "radix" >>= | |
checkDisplay "Hello there, radix!" >>= | |
checkPrompt "Friend's name? " "ace" >>= | |
checkDisplay "Greets, ace." >>= | |
checkReturn ("radix", "ace") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment