Fix chapter 21

master
Gaël Depreeuw 6 years ago
parent ae9e3118df
commit 98e3373c8c
  1. 169
      21-traversable/21-traversable.md
  2. 2
      21-traversable/21.12-chapter-exercises.md
  3. 10
      21-traversable/src/chapter.hs

@ -0,0 +1,169 @@
# Chapter 21 Traversable
## 21.3 sequenceA
```haskell
-- Why: (fmap . fmap) sum Just [1, 2, 3] = Just 6
-- Let's check the types
fmap :: Functor f => (a -> b) -> f a -> f b
(fmap . fmap) :: (Functor f1, Functor f2) => (a -> b) -> f1 (f2 a) -> f1 (f2 b)
(fmap . fmap) sum :: (Num a, Foldable t, Functor f1, Functor f2) =>
f1 (f2 (t a)) -> f1 (f2 a)
(fmap . fmap) sum Just :: -- Just :: b -> Maybe b
-- Just :: (->) b (Maybe b)
-- for this to correspond with f1 (f2 (t a))
-- f1 is '(->) b'
-- f2 is Maybe
-- b is 't a'
-- so f1 (f2 a) is (->) (t a) (Maybe a)
(Num a, Foldable t) => t a -> Maybe a
-- A good way to see this is that we are lifting the 'sum' over the function
-- functor and the Maybe functor produced as a result of the function functor
--
-- Just :: (->) a (Maybe a)
--
-- And we are lifting (sum :: Foldable t => t a -> a) over (->) a and Maybe.
-- Notice that the a in Just needs to be specialized in a t a to function as
-- the input for sum, i.e
--
-- Just' :: Foldable t => (->) (t a) (Maybe (t a))
--
-- We can now apply (fmap . fmap) sum and get:
-- (fmap . fmap) sum Just :: Foldable t => (->) (t a) (Maybe (t a))
-- It might be helpful to look at the generalized form:
--
-- (fmap . fmap) h1 h2 :: ?
--
(fmap . fmap) :: (Functor f1, Functor f2) => (a -> b) -> f1 (f2 a) -> f1 (f2 b)
(fmap . fmap) h1 :: (Functor f1, Functor f2) => f1 (f2 a) -> f1 (f2 b)
-- if we now want to add h2, with h2 being: b' -> c', we can deduce that
-- (->) b' is the f1 functor and c' is 'f2 a'
(fmap . fmap) h1 :: Functor f => (b' -> f a) -> (b' -> f b)
-- A couple of points to remember:
-- b' is an input of h2 and a is an input of h1, so h2 needs to be a function
-- that return returns an input from h1 in a functor (e.g. with Just this can
-- take a 'Foldable t => t a' and returns a Maybe (t a))
-- This implies that there are restrictions imposed on h2:
-- h2 needs to return a functor which contains an input type of h1
-- Applying h2 just gives:
(fmap . fmap) h1 h2 :: (Functor f) => b' -> f b
-- Does this restriction on h2 hold for 'Just'?
-- Consider that sum :: Foldable t => t a -> a
-- And Just :: a -> Maybe a, with a being more generic than 't a', we can
-- indeed say that the resulting a in 'Maybe a' can be of type 't a'.
-- We can rewrite (fmap . fmap) h1 h2 as:
--
-- fmap h1 . h2
--
-- So (fmap . fmap) sum Just can be written as fmap sum . Just
-- Another example with different types accross the board:
foo :: String -> Maybe [Bool]
foo [] = Just []
foo (x:xs) = case foo xs of
Just xs -> case x of
't' -> Just $ True : xs
'f' -> Just $ False : xs
otherwise -> Nothing
otherwise -> Nothing
bar :: [Bool] -> Integer
bar = foldr (\b c -> if b then c + 1 else c - 1) 0
-- where (fmap . fmap) bar foo = fmap bar . foo
```
## 21.4 traverse
Why is traverse not defined as:
`traverse :: (Functor f, Traversable t) => (a -> f b) -> t a -> f (t b)`
Maybe let's ask ourselves why sequenceA cannot be defined as such:
`sequenceA :: (Traversable t, Functor f) => t (f a) -> f (t a)`
Let's try to implement it:
```haskell
-- Without applicative, but functor allowed
instance Traversable [] where
sequenceA [] = ??? -- we have no way of putting this in a functor, we
-- would need pure at least...
sequenceA (x:xs) = ??? -- we have an x :: f a
-- and an xs :: [f a]
-- We can turn the xs into f [a] via sequenceA:
-- sequenceA xs, but now we need to concatenate
-- 'f a' and 'f [a]' with only using fmap and this
-- is impossible. We can fmap (:) into 'f a', but
-- then we need (<*>) to apply this to 'f [a]'
-- with applicative it works:
instance Traversable [] where
sequenceA [] = pure []
sequenceA (x:xs) = (:) <$> x <*> sequenceA xs
```
## 21.6 morse code revisited
Why `(sequence .) . fmap` and not `sequence . fmap`
```haskell
fmap :: Functor f => (a -> b) -> (f a -> f b)
sequence :: (Monad m, Traversable t) => t (m a) -> m (t a)
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(.) sequence :: (Monad m, Traversable t) => (a -> t (m b)) -> (a -> m (t b))
(.) sequence fmap :: -- a :: (a' -> b')
-- t (m b) :: (->) (f a') (f b')
-- t :: (->) (f a') i.e. (->) (f a') must be Traversable
-- m b :: f b' i.e f shoulde be a Monad
(Monad m, Traversable (->) (f a)) =>
(a -> b) -> m (m a -> b)
-- Which is not really wat we want...
-- However, if you check (.) sequence, then it looks close to what we want
(.) ((.) sequence) :: (Monad m, Traversable t) =>
(a -> (b -> t (m c))) -> (a -> (b -> m (t c)))
(.) ((.) sequence) fmap :: -- a = (a' -> b')
-- b -> t (m c) = (f a') -> f b'
-- b = f a'
-- t (m c) = f b'
-- t = f (A traversable t is also a functor, see
-- its definition)
-- b' :: m c
(Monad m, Traversable t) =>
(a' -> m c) -> (t a' -> m (t c))
```
## 21.10 Traversable Laws
```haskell
Compose :: f (g a) -> Compose f g a
f :: Applicative f => a -> f b
g :: Applicative g => a -> f b -- bascause of traverse g
fmap g :: (Applicative f1, Functor f2) => f2 a -> f2 (f1 b)
fmap g . f :: (Applicative f1, Applicative f2) => a -> f2 (f1 b)
Compose . (fmap g . f) :: (Applicative f1, Applicative f2) =>
a -> Compose f g b
traverse (Compose . fmap g . f) ::
(Applicative f1, Applicative f2, Traversable t) =>
t a -> Compose f1 f2 (t b)
traverse f :: (Applicative f, Traversable t) => t a -> f (t b)
fmap (traverse g) :: (Applicative f1, Applicative f2, Traversable t) =>
f1 (t a) -> f1 (f2 (t b))
fmap (traverse g) . traverse f ::
(Applicative f1, Applicative f2, Traversable t) =>
t a -> f1 (f2 (t b))
Compose . fmap (traverse g) . traverse f ::
(Applicative f1, Applicative f2, Traversable t) =>
t a -> Compose f1 f2 (t b)
```
## 21.12 Chapter Exercises
see [src/chapter.hs](./src/chapter.hs)

@ -1,2 +0,0 @@
# Chapter Exercises
see src/chapter.hs

@ -78,7 +78,7 @@ instance Foldable (Three a b) where
foldMap f (Three _ _ c) = f c
instance Traversable (Three a b) where
traverse f (Three a b c) = Three a b <$> f c
instance (Arbitrary a, Arbitrary b, Arbitrary c) =>
instance (Arbitrary a, Arbitrary b, Arbitrary c) =>
Arbitrary (Three a b c) where
arbitrary = Three <$> arbitrary <*> arbitrary <*> arbitrary
instance (Eq a, Eq b, Eq c) => EqProp (Three a b c) where (=-=) = eq
@ -124,14 +124,14 @@ data S n a = S (n a) a deriving (Eq, Show)
instance Functor n => Functor (S n) where
fmap f (S n a) = S (fmap f n) (f a)
instance Foldable n => Foldable (S n) where
foldMap f (S n a) = foldMap f n <> f a
foldMap f (S n a) = foldMap f n <> f a
instance Traversable n => Traversable (S n) where
traverse f (S n a) = S <$> traverse f n <*> f a
instance (Functor n, Arbitrary (n a), Arbitrary a) => Arbitrary (S n a) where
arbitrary = S <$> arbitrary <*> arbitrary
-- The EqProp instance from the book fails. No idea why, the logic seems
-- sound?
-- instance (Applicative n, Testable (n Property), EqProp a) =>
-- instance (Applicative n, Testable (n Property), EqProp a) =>
-- EqProp (S n a) where
-- (S x y) =-= (S p q) = (property $ (=-=) <$> x <*> p) .&. (y =-= q)
instance (Eq (n a), Eq a) => EqProp (S n a) where (=-=) = eq
@ -153,7 +153,7 @@ instance Foldable Tree where
instance Traversable Tree where
traverse _ Empty = pure Empty
traverse f (Leaf a) = Leaf <$> f a
traverse f (Node t a t') =
traverse f (Node t a t') =
Node <$> (traverse f t) <*> f a <*> traverse f t'
-- probably not the best distribution for a tree.
-- Should probably have it have a certain depth similar to []
@ -169,7 +169,7 @@ instance (Eq a) => EqProp (Tree a) where (=-=) = eq
-- fmap :: Functor f => (a -> b) -> f a -> f b
-- foldMap :: (Monoid m, Foldable t) => (a -> m) -> t a -> m
-- foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
-- foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
-- traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
main :: IO ()

Loading…
Cancel
Save