{-# LANGUAGE GADTs #-}
-- Applicative, part II
-- More example Applicative instances
-- We've seen:
-- Maybe
-- Parser
-- []
-- ZipList
-- ((->) e)
-- pure g <*> x = fmap g x
class Functor f => Applicative' f where
pure' :: a -> f a
(<*.>) :: f (a -> b) -> f a -> f b
instance Applicative' [] where
-- singleton list
pure' a = [a]
-- cross/Cartesian product
-- (all pairings of function+argument)
[] <*.> xs = []
(f:fs) <*.> xs = map f xs ++ (fs <*.> xs)
-- std lib: ZipList
newtype Zippy a where
Z :: [a] -> Zippy a
deriving Show
instance Functor Zippy where
fmap g (Z xs) = Z (fmap g xs)
instance Applicative' Zippy where
pure' a = Z (repeat a)
Z fs <*.> Z xs = Z (zipWith ($) fs xs)
-- Z [] <*.> _ = Z []
-- _ <*.> Z [] = Z []
-- Z (f:fs) <*.> Z (x:xs) =
-- case Z fs <*.> Z xs of
-- Z ys -> Z (f x : ys)
-- pure :: a -> [a]
-- doubleton list?
-- n-le-ton list?
-- (<*>) :: [a -> b] -> [a] -> [b]
-- zip (truncate to length of shorter)?
-- always return empty list?
-- X doesn't satsify law
-- fmap = (.)
instance Applicative' ((->) e) where
-- pure' :: a -> ((->) e) a
-- pure' :: a -> (e -> a)
pure' a _ = a
-- (<*>) :: ((->) e) (a -> b) -> ((->) e) a -> ((->) e) b
-- (<*>) :: (e -> (a -> b)) -> (e -> a) -> (e -> b)
-- (<*>) :: (e -> a -> b) -> (e -> a) -> e -> b
x <*.> y = \e -> x e (y e)
------------------------------------------------------------
-- Programming against the Applicative API
-- one pattern we've seen:
--
-- g <$> x <*> y
-- liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
-- liftA2 g x y = g <$> x <*> y
-- liftA3 :: Applicative f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d
-- liftA3 g x y z = g <$> x <*> y <*> z
-- g <$> x :: f (b -> c -> d)
-- (g <$> x) <*> y :: f (c -> d)
-- ((g <$> x) <*> y) <*> z :: f d
pair :: Applicative f => f a -> f b -> f (a,b)
pair fa fb = (,) <$> fa <*> fb -- liftA2 (,)
sequenceAL :: Applicative f => [f a] -> f [a]
sequenceAL [] = pure []
sequenceAL (fa:fas) = (:) <$> fa <*> sequenceAL fas
-- fa :: f a
-- fas :: [f a]
-- sequenceA fas :: f [a]
mapA :: Applicative f => (a -> f b) -> [a] -> f [b]
mapA g as = sequenceAL (map g as)
-- mapA g = sequenceAL . map g
-- mapA = (sequenceAL .) . map -- DON'T TRY THIS AT HOME
-- Traversable is characterized by the above
-- for :: Applicative f => [a] -> (a -> f b) -> f [b]
-- Another Functor / Applicative: IO
-- A value of type IO a is a "first-class imperative program"
-- which, when executed, has some I/O effects and produces an a.
hello :: IO ()
hello = putStrLn "hello, world"
hellohello :: IO ()
hellohello = hello *> hello
main :: IO ()
main = hellohello *> (readLn :: IO Int) *> putStrLn "That was dumb"