Skip to content

Instantly share code, notes, and snippets.

@qoelet
Created May 14, 2019 09:26
Show Gist options
  • Save qoelet/c0206d27ffaa4d592c7e62b4edb2bd38 to your computer and use it in GitHub Desktop.
Save qoelet/c0206d27ffaa4d592c7e62b4edb2bd38 to your computer and use it in GitHub Desktop.
Playing with arrows
module Arrows where
import Control.Arrow
import System.Directory (doesDirectoryExist)
-- `arr` lifts a function to an arrow
-- arr :: (b -> c) -> a b c
-- e.g. pure function (+ 2) :: Integer -> Integer
-- b :: Integer
-- c :: Integer
foo :: Arrow a => a Integer Integer
foo = arr (+ 2)
bar :: Arrow a => a Integer String
bar = arr show
-- e.g. monadic function putStrLn :: String -> IO ()
baz :: Kleisli IO String ()
baz = Kleisli putStrLn
-- e.g. composing these arrows
qux :: Kleisli IO Integer ()
qux = foo >>> bar >>> baz
quux :: Kleisli IO () ()
quux = Kleisli (\_ -> putStrLn "huhu")
-- Arrows make the dependence on input explicit
-- An arrow type of a b c is the application of
-- the parametrised type a to the two parameters
-- b and c
--
-- `return`, with type a -> m a, converts a value
-- into a computation while its analogue for arrows
-- `arr`, with type (b -> c) -> a b c, converts
-- a function from input to output into a computation
--
-- The analogue of `>>=` is just composition of
-- arrows
--
-- For any monad m, functions of type a -> m b are
-- potential arrows we name Kleisli
--
-- Arrows generalise monads;
-- for every monad type, there is a corresponding
-- arrow type
-- More sequencing actions
-- *Arrows> runKleisli (first foo) (4, 5)
-- (6,5)
-- *Arrows> runKleisli (second foo) (4, 5)
-- (4,7)
faux :: Arrow a => a (Integer, Integer) (Integer, Integer)
faux = foo *** foo
pas :: Arrow a => a Integer (Integer, Integer)
pas = foo &&& foo
-- An example of a program expressed via monads
mProgram :: IO String
mProgram
= doesDirectoryExist "/foo/bar"
>>= (\r -> if r then putStrLn "yes" else putStrLn "no")
>> return "huhu"
-- Above rewritten via arrows
aProgram :: IO String
aProgram
= runKleisli (Kleisli doesDirectoryExist
>>> (arr $ \r -> if r then "yes" else "no")
>>> Kleisli putStrLn
>>> (Kleisli $ \_ -> return "huhu")) "/foo/bar"
main :: IO ()
main = do
(runKleisli (foo >>> bar >>> baz)) 4
(runKleisli (qux >>> quux)) 4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment