Last active
August 7, 2016 19:28
-
-
Save gelisam/7ab28af444c37b456dec633b6a61b69c to your computer and use it in GitHub Desktop.
Scribbles from a discussion with Daniel Spiewak at Scala Up North
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
-- in response to https://gist.github.com/djspiewak/443d37b5d93b92685ce3579cde27b627 | |
-- an example of the problem | |
data Op a where | |
-- returns one row now and a second row later if you want it | |
Select :: String -> Op (Row, Prog Row) | |
type Prog a = Free Op a | |
interpret :: Prog a -> IO a | |
interpret (Return x) = return x | |
interpret (Bind (Select sql) cc) = do | |
h <- runSql sql | |
firstRow <- nextRow h | |
let getSecondRow = nextRow h | |
-- doesn't type check: getSecondRow has type (IO Row) but we need (Prog Row) | |
interpret (cc (firstRow, getNextRow)) | |
-- | |
-- first solution: a hidden constructor which users aren't supposed to use | |
data Op a where | |
Select :: String -> Op (Row, Prog Row) | |
HiddenIO :: IO a -> Op a | |
type Prog a = Free Op a | |
interpret :: Prog a -> IO a | |
interpret (Return x) = return x | |
interpret (Bind (Select sql) cc) = do | |
h <- runSql sql | |
firstRow <- nextRow h | |
let getSecondRow = HiddenIO (nextRow h) | |
interpret (cc (firstRow, getNextRow)) | |
interpret (Bind (HiddenIO io) cc) = do | |
a <- io | |
interpret (cc a) | |
-- | |
-- but users *can* use it, we're not making illegal computations unrepresentable. | |
-- second solution: parameterize over IO | |
data Op io a where | |
Select :: String -> Op io (Row, Prog Row) | |
HiddenIO :: io a -> Op io a | |
type Prog io a = Free (Op io) a | |
-- now a program which is polymorphic in io cannot use the hidden constructor at all, so we cannot represent illegal computations | |
prog :: forall io. Prog io (Row, Row) | |
prog = do | |
(row1, getRow2) <- liftFree (Select "...") | |
row2 <- getRow2 | |
return (row1, row2) | |
interpret :: Prog IO a -> IO a | |
interpret (Return x) = return x | |
interpret (Bind (Select sql) cc) = do | |
h <- runSql sql | |
firstRow <- nextRow h | |
let getSecondRow = HiddenIO (nextRow h) | |
interpret (cc (firstRow, getNextRow)) | |
interpret (Bind (HiddenIO io) cc) = do | |
a <- io | |
interpret (cc a) | |
-- but interpret expects a (Prog IO a), which *can* represent illegal computations. | |
-- third solution: the interpreter should ask for a polymorphic program, just like runST | |
public_interpreter :: (forall io. Prog io a) -> IO a | |
public_interpreter prog = interpret prog | |
--- | |
He liked my solution :) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment