parent
							
								
									ae9e3118df
								
							
						
					
					
						commit
						98e3373c8c
					
				
				 3 changed files with 174 additions and 7 deletions
			
			
		| @ -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 | ||||
					Loading…
					
					
				
		Reference in new issue