Reading group: Learn You a Haskell: Part Six

This Friday, March 21, we’ll cover chapters 10 and 11:

  • Functionally Solving Problems
  • Applicative Functors

With Applicative Functors, we’ll start getting into some of the mindblowingly awesome parts of Haskell (and hopefully Pat won’t be too bored this time).

Forgot to post this last week!

We discussed:

  • Bytestrings
  • Review: Functor, fmap, Either
  • IO as Functor
  • Functions as Functor (composition)
  • fmap with functions and currying
  • Functor laws
  • Applicative, pure, <*>, and <$>
  • IO as Applicative
  • ZipList
  • Applicative laws
  • liftA2, sequenceA

I provided an example to summarize how to use Functor and Applicative:

import Control.Applicative

-- ghci> double 5
-- 10
double :: Int -> Int
double i = i * 2

-- ghci> smaller 2 3
-- 2
smaller :: Int -> Int -> Int
smaller x y
    | x < y = x
    | otherwise = y

-- ghci> maybeDouble $ Just 5
-- Just 10
-- ghci> maybeDouble Nothing
-- Nothing
maybeDouble :: Maybe Int -> Maybe Int

-- Long version
maybeDouble (Just x) = Just $ double x
maybeDouble Nothing = Nothing

-- Using fmap
maybeDouble = fmap double

-- ghci> maybeSmaller (Just 2) (Just 3)
-- Just 2
-- ghci> maybeSmaller (Just 2) Nothing
-- Nothing
-- ghci> maybeSmaller Nothing (Just 3)
-- Nothing
maybeSmaller :: Maybe Int -> Maybe Int -> Maybe Int

-- Long version
maybeSmaller (Just x) (Just y) = Just $ smaller x y
maybeSmaller _ _ = Nothing

-- Using applicative style
maybeSmaller x y = smaller <$> x <*> y

-- Using liftA2
maybeSmaller = liftA2 smaller

We also pointed out that using fmap or liftA2 instead of destructuring allows you to be more abstract. For example, we can rewrite the functions in that example to use Functor f => f Int instead of Maybe Int to make them work within other Functors like IO or List.