Skip to content

Instantly share code, notes, and snippets.

@gelisam
Last active August 7, 2016 19:28
Show Gist options
  • Save gelisam/7ab28af444c37b456dec633b6a61b69c to your computer and use it in GitHub Desktop.
Save gelisam/7ab28af444c37b456dec633b6a61b69c to your computer and use it in GitHub Desktop.
Scribbles from a discussion with Daniel Spiewak at Scala Up North
-- 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