CIS 194 Lecture 10 & 11
To begin, consider the following:
type Name = Text
data Employee = Employee
{ name :: Name
, phone :: Text
} deriving ShowEmployee :: Name -> String -> Employeethus...
Employee:: Maybe Name -> Maybe String -> Maybe EmployeeSuch data ?
Employee :: Name -> String -> EmployeeMuch inputs ?
Employee :: [Name] -> [String] -> [Employee]Employee :: (e -> Name) -> (e -> String) -> (e -> Employee)Wow ?
wibbly :: (a -> b -> c) -> f a -> f b -> f cIt's a Unix system... I know this...
fmap :: (a -> b) -> f a -> f bWe have an extra wobbly though... so maybe...
fmap2 :: (a -> b -> c) -> f a -> f b -> f c
fmap2 f fa fb = undefinedWell, no.. not really.
h :: a -> b -> c
fa :: f a
fb :: f bh :: a -> (b -> c)
fmap h :: f a -> f (b -> c)
fmap h fa :: f (b -> c)fmap :: (a -> b) -> f a -> f bDammit...
finally, he gets to the point...
Formally:
class Functor f => Applicative f where
pure :: a -> f a
<*> :: f (a -> b) -> f a -> f bThere is only one "interesting" law for Applicative
f `fmap` x === pure f <*> xNote that every Applicative is a Functor, by definition.
fmap2 redux
Recall:
h :: a -> b -> c
fa :: f a
fb :: f b
fmap h :: f a -> f (b -> c)
fmap h fa :: f (b -> c)<*> :: Applicative f => f (a -> b) -> f a -> f bNew hotness
fmap :: Functor f => (a -> b) -> f a -> f bOld and busted (not really)
Now
fmap2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
fmap2 h fa fb = (h `fmap` fa) <*> fbApplicative was built by helpful types (ha!), so we have some extra goodies.
fmap2 = liftA2(<$>) :: Functor f => (a -> b) -> f a -> f b
(<$>) = fmapfmap has an infix version:
Thus
liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
liftA2 f a b = (f <$> a) <*> bCan we build a bigger boat?
liftA3 :: Applicative f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d
liftA3 h fa fb fc = h <$> fa <*> fb <*> fcOperator precedence and associativity means we don't need piles of parentheses
What about 'pure' ?
While 'apply' (angle butt) handles the principle of 'contextual application'.
'pure' can be used to shift some function into some 'f'
pure :: a -> f a<*> :: f (a -> b) -> f a -> f bpure sum = ((Applicative f, Num a) => f ([a] -> a))fangly :: (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c
fangly c ma mb = pure c <*> ma <*> mbExamples ! Woo!
class Functor f => Applicative f where
pure :: a -> f a
<*> :: f (a -> b) -> f a -> f binstance Applicative Maybe whereinstance Applicative Maybe where
pure a = ..instance Applicative Maybe where
pure a = Just a
Alternatively ... Point free stylezz
pure = Justinstance Applicative Maybe where
pure = Just
Nothing <*> ?? = ..
?? <*> Nothing = ..
Just f <*> Just g = ..instance Applicative Maybe where
pure = Just
Nothing <*> ? = ..
? <*> Nothing = ..
Just f <*> Just g = ..instance Applicative Maybe where
pure = Just
Nothing <*> _ = Nothing
_ <*> Nothing = Nothing
Just f <*> Just g = ..instance Applicative Maybe where
pure = Just
Nothing <*> _ = Nothing
_ <*> Nothing = Nothing
Just f <*> Just g = Just (f g)Isn't that just functor? What use is having "yet another abstraction"?
The difference between the two, on the surface, is small and doesn't present itself as a great leap...
But Applicative represents a "model of computation" that Functor does not.
(<$>) :: (a -> b) -> f a -> f b
(<*>) :: f (a -> b) -> f a -> f bAs you already aware there are multiple levels of abstraction
Implementing your Applicative or Monad instances can be thought of as just one level. The "raw Haskell" level...
Once you have done that, you are able to move up a level.
Once you have the tiny moving parts...
You are able to combine them to create more advanced mechanisms.
Without needing to be (too) concerned with the underlying implementation.
You'll discover this in the homework !!
Oh yes... you have homework...
A double batch in fact...
Quit whining...
._.
Applicative is awesome. THE END.
Yay it's over! Why do I keep agreeing to give presentations... ???? :(
Applicative Lecture 1:
http://www.seas.upenn.edu/~cis194/spring13/lectures/10-applicative.html
Applicative Lecture 2:
http://www.seas.upenn.edu/~cis194/spring13/lectures/11-applicative2.html
Homework #1 :
http://www.seas.upenn.edu/~cis194/spring13/extras/10-applicative/AParser.hs
Homework #2 :
http://www.seas.upenn.edu/~cis194/spring13/extras/11-applicative2/AParser.hs
http://www.seas.upenn.edu/~cis194/spring13/extras/11-applicative2/SExpr.hs
Do the home work in order, otherwise you'll be a sad panda...
data MyConf = MyConf
{ _remoteHost :: HostName
, _remotePort :: Int
, _setting1 :: SettingType
, _setting2 :: OtherSetting
}
-- our get thing from the loaded conf function.
getFromConf :: Config -> Text -> IO a
buildConfig :: FilePath -> IO MyConf
buildConfig fp = do
rHost <- getFromConf c "remote.host"
rPort <- getFromConf c "remote.port"
set1 <- getFromConf c "setting1"
set2 <- getFromConf c "other.setting2"
return $ MyConf rHost rPort set1 set2
where
c = loadConfigFile fp
Using `do` notation, and basic constructor usage.
`MyConf` is lifted into context using `return`
buildConfig :: FilePath -> IO MyConf
buildConfig fp = MyConf
<$> getFromConf c "remote.host"
<*> getFromConf c "remote.port"
<*> getFromConf c "setting1"
<*> getFromConf c "other.setting2"
where
c = loadConfigFile fpUsing applicative...
lift `MyConf` into context with fmap (<$>)
Continue computation with apply (<*>)