Skip to content

Instantly share code, notes, and snippets.

@laser
Last active August 29, 2015 14:04
Show Gist options
  • Save laser/e2a26007537c6227a95d to your computer and use it in GitHub Desktop.
Save laser/e2a26007537c6227a95d to your computer and use it in GitHub Desktop.
Bro, do you even liftA2?
module Main where
import Control.Applicative
-- represents our API - its constructor takes two functions
--
data API = API { apiDouble :: Integer -> Integer, apiTriple :: Integer -> Integer }
-- run a pure function as a computation in the IO monad.
-- note that the function won't be run until you bind the
-- monad. the good news is that the IO monad instantiates
-- Functor and Applicative, which let us use <$> and <*>
--
taint :: a -> IO a
taint f = do
putStrLn "thou hast been tainted by IO!"
return $ f
-- the Functor instance provided by IO:
--
-- instance Functor IO where
-- fmap f action = do
-- result <- action
-- return (f result)
-- the Applicative instance provided by IO:
--
-- instance Applicative IO where
-- pure = return
-- a <*> b = do
-- f <- a
-- x <- b
-- return (f x)
-- some pure functions to expose via the API type
--
dbl :: Integer -> Integer
dbl x = x * 2
trpl :: Integer -> Integer
trpl x = x * 3
-- take a constructor function t: (Integer -> Integer) -> (Integer -> Integer) -> b
-- a functor of type F holding a function that goes from (Integer -> Integer)
-- and a second functor of type F that goes from (Integer -> Integer)
-- and combine these to return a functor of type F that holds a value resulting
-- from running the constructor function t
--
makeAPI :: Applicative f => t -> f (Integer -> Integer) -> f (Integer -> Integer) -> f API
makeAPI constructor functor1 functor2 = step2 (step1 API functor1) functor2
step1 :: Functor f => (a -> b) -> f a -> f b
step1 constructor functor = constructor <$> functor
step2 :: Applicative f => f (a -> b) -> f a -> f b
step2 step1Result functor = step1Result <*> functor
-- demonstrate the equivalency of makeAPI and API <$> f1 <*> f2
--
main :: IO ()
main = do
api <- API <$> taint dbl <*> taint trpl
api2 <- makeAPI (API) (taint dbl) (taint trpl)
putStrLn $ show $ apiDouble api 5 -- 10
putStrLn $ show $ apiTriple api2 10 -- 30
return ()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment