From a7290501fc70a862855d20296752f4a17a747a13 Mon Sep 17 00:00:00 2001 From: Juan Manuel Gimeno Illa Date: Sat, 21 Apr 2018 14:38:42 +0200 Subject: [PATCH] WIP: Finished Applicatives --- typeclasses/Makefile | 12 +- typeclasses/typeclasses-nonet.html | 112 -------------- typeclasses/typeclasses.html | 229 ----------------------------- typeclasses/typeclasses.lhs | 223 ++++++++++++++++++++++++---- 4 files changed, 202 insertions(+), 374 deletions(-) delete mode 100644 typeclasses/typeclasses-nonet.html delete mode 100644 typeclasses/typeclasses.html diff --git a/typeclasses/Makefile b/typeclasses/Makefile index 38f3158..6166284 100644 --- a/typeclasses/Makefile +++ b/typeclasses/Makefile @@ -1,17 +1,19 @@ slides = typeclasses -$(slides).html: $(slides).lhs +$(slides).html $(slides)-nonet.html: $(slides).lhs pandoc -s --webtex -t slidy $(slides).lhs -o $(slides).html - -$(slides)-nonet.html: $(slides).lhs pandoc -s --webtex -t slidy -V slidy-url:http://localhost:8000/ $(slides).lhs -o $(slides)-nonet.html -.PHONY: clean runserver clean: rm -f $(slides).html $(slides)-nonet.html +open: $(slides).html + open $(slides).html + runserver: python -m http.server -open: $(slides)-nonet.html +open-nonet: $(slides)-nonet.html open http://localhost:8000/$(slides)-nonet.html + +.PHONY: clean open runserver open-nonet \ No newline at end of file diff --git a/typeclasses/typeclasses-nonet.html b/typeclasses/typeclasses-nonet.html deleted file mode 100644 index ef63533..0000000 --- a/typeclasses/typeclasses-nonet.html +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - - Remembering typeclasses - - - - - - -
-

Remembering typeclasses

-

-Juan Manuel Gimeno -

-

someday

-
-
-

Index

- -
-
import Prelude hiding (Eq(..)
-                      )
-
-
-
-

Typeclasses and instances

- -
class Eq a where
-  (==) :: a -> a -> Bool
-  (/=) :: a -> a -> Bool
-  x /= y = not (x == y)
-  x == y = not (x /= y)
- -
instance Eq a => Eq [a] where
-  []     == []     = True 
-  _      == []     = False
-  []     == _      = False
-  (a:as) == (b:bs) = (a == b) && (as == bs)
-
-
-

Monoid

-
class Monoid a where
-    mempty  :: a
-    mappend :: a -> a -> a
-
-    mconcat :: [a] -> a
-    mconcat = foldr mappend mempty
-
- - diff --git a/typeclasses/typeclasses.html b/typeclasses/typeclasses.html deleted file mode 100644 index d16e929..0000000 --- a/typeclasses/typeclasses.html +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - Typclassopedia (or the long path to lenses) - - - - - - -
-

Typclassopedia (or the long path to lenses)

-

-Juan Manuel Gimeno -

-

someday

-
-
-

Index

- -
-
import Prelude hiding (Eq(..)
-                      ,Functor(..)
-                      ,Monoid(..)
-                      )
-
-
-
-

Typeclasses and instances

- -
class Eq a where
-  (==) :: a -> a -> Bool
-  (/=) :: a -> a -> Bool
-  x /= y = not (x == y)
-  x == y = not (x /= y)
- -
instance Eq a => Eq [a] where
-  []     == []     = True 
-  _      == []     = False
-  []     == _      = False
-  (a:as) == (b:bs) = (a == b) && (as == bs)
-
-
-

Typeclasses

-
-(Typeclasses described in the Typeclassopedia) -

(Typeclasses described in the Typeclassopedia)

-
-
-
-

Functor

-
class Functor f where
-  fmap :: (a -> b) -> f a -> f b
- -
-- Data.Functor / Control.Applicative
-(<$>) = fmap
-

Laws

-
fmap id      = id
-fmap (f . g) = fmap f . fmap g
- -
-
-

Functor

-
instance Functor [] where
-  fmap = map
-
instance Functor Maybe where
-  fmap _ Nothing  = Nothing
-  fmap f (Just a) = Just (f a)
-
instance Functor Either a where
-  fmap _ (Left a)  = Left a
-  fmap f (Right b) = Right (f b)
-
-- writer
-instance Functor ((,) a) where
-  fmap f (a, x) = (a, f x)
-
-- reader
-instance Functor ((->) a) where
-  fmap = (.)
-
-
-

Functor

- -
-- Data.Functor.Identity 
-newtype Identity a = Identity { runIdentity :: a }
-
-instance Functor Identity where
-  fmap f (Identity a) = Identity (f a)
-
-- Data.Functor.Const
-newtype Const a b = Const { getConst :: a }
-
-instance Functor (Const a) where
-  fmap _ (Const a) = Const a
-
-
-

Monoid

-
class Monoid a where
-   mempty  :: a
-   mappend :: a -> a -> a
-
-   mconcat :: [a] -> a
-   mconcat = foldr mappend mempty
-
-- Data.Monoid
-(<>) = mappend 
-

Laws

-
(x <> y) <> z = x <> (y <> z) -- associativity
-mempty <> x = x               -- left identity
-x <> mempty = x               -- right identity
-
-
-

Monoid

-
instance Monoid [a] where
-   mempty  = []
-   mappend = (++)
-
newtype Sum a = Sum { getSum :: a }
-
-instance Num a => Monoid (Sum a) where
-   mempty = Sum 0
-   Sum x `mappend` Sum y = Sum (x + y)
-
newtype Product a = Product { getProduct :: a }
-
-instance Num a => Monoid (Product a) where
-   mempty = Product 1
-   Product x `mappend` Product y = Product (x * y)
-
-
-

Applicative

-
class Functor f => Applicative f where
-  pure :: a -> f a
-  (<*>) :: f (a -> b) -> f a -> f b  -- apply
-  (<*>) = liftA2 id
-  liftA2 :: (a -> b -> c) -> f a -> f b -> f c
-  liftA2 f x = (<*>) (fmap f x)
-

Functors which can:

- -

Laws

-
pure id <*> v = v                            -- Identity
-pure f <*> pure x = pure (f x)               -- Homomorphism
-u <*> pure y = pure ($ y) <*> u              -- Interchange
-pure (.) <*> u <*> v <*> w = u <*> (v <*> w) -- Composition
-fmap f x = pure f <*> x                      -- Relation with Functor
-
-
-

Applicative

-
-
-

Foldable

-
-
-

Traversable

-
-
-

Bibliography

- -
- - diff --git a/typeclasses/typeclasses.lhs b/typeclasses/typeclasses.lhs index 53e7e22..79b0f7d 100644 --- a/typeclasses/typeclasses.lhs +++ b/typeclasses/typeclasses.lhs @@ -1,6 +1,6 @@ -% Typclassopedia (or the long path to lenses) +% Typeclassopedia (first step in the long path to lenses) % Juan Manuel Gimeno -% someday +% 25 April 2018 Index ===== @@ -15,9 +15,10 @@ Index
-> import Prelude hiding (Eq(..) -> ,Functor(..) -> ,Monoid(..) +> import Prelude hiding ( Eq(..) +> , Functor(..) +> , Monoid(..) +> , Applicative(..) > )
@@ -58,10 +59,14 @@ Functor - fmap lifts a function from the _"normal world"_ to the _"`f` world"_ (the __context__ defined by the functor) -```haskell --- Data.Functor / Control.Applicative -(<$>) = fmap -``` +
+ +> (<$>) :: Functor f => (a -> b) -> f a -> f b + +
+ +> -- Data.Functor +> (<$>) = fmap Laws ---- @@ -85,7 +90,7 @@ Functor > fmap _ Nothing = Nothing > fmap f (Just a) = Just (f a) -> instance Functor Either a where +> instance Functor (Either a) where > fmap _ (Left a) = Left a > fmap f (Right b) = Right (f b) @@ -114,49 +119,54 @@ Functor > instance Functor (Const a) where > fmap _ (Const a) = Const a - Monoid ====== > class Monoid a where -> mempty :: a -> mappend :: a -> a -> a +> mempty :: a +> mappend :: a -> a -> a > -> mconcat :: [a] -> a -> mconcat = foldr mappend mempty +> mconcat :: [a] -> a +> mconcat = foldr mappend mempty -```haskell --- Data.Monoid -(<>) = mappend -``` +
+ +> (<>) :: Monoid m => m -> m -> m + +
+ +> -- Data.Monoid +> (<>) = mappend + +* types whose values which can be combined / accumulated Laws ---- ```haskell +mempty <> x = x -- Left identity +x <> mempty = x -- Right identity (x <> y) <> z = x <> (y <> z) -- associativity -mempty <> x = x -- left identity -x <> mempty = x -- right identity ```` Monoid ====== > instance Monoid [a] where -> mempty = [] -> mappend = (++) +> mempty = [] +> mappend = (++) > newtype Sum a = Sum { getSum :: a } > > instance Num a => Monoid (Sum a) where -> mempty = Sum 0 -> Sum x `mappend` Sum y = Sum (x + y) +> mempty = Sum 0 +> Sum x `mappend` Sum y = Sum (x + y) > newtype Product a = Product { getProduct :: a } > > instance Num a => Monoid (Product a) where -> mempty = Product 1 -> Product x `mappend` Product y = Product (x * y) +> mempty = Product 1 +> Product x `mappend` Product y = Product (x * y) Applicative =========== @@ -171,7 +181,7 @@ Applicative Functors which can: * embed pure expressions (`pure`) -* sequence computations and combine their results (`<*>` and `liftA2`) +* __sequence__ computations and __combine__ their results (`<*>` and `liftA2`) Laws ---- @@ -187,6 +197,163 @@ fmap f x = pure f <*> x -- Relation with Functor Applicative =========== +> instance Applicative Maybe where +> pure = Just +> (Just f) <*> (Just x) = Just (f x) +> _ <*> _ = Nothing + +> instance Applicative [] where +> pure x = [x] +> fs <*> xs = [f x | f <- fs, x <- xs] -- chooses order + +> newtype ZipList a = ZipList { getZipList :: [a] } +> +> instance Applicative ZipList where +> pure x = ZipList (repeat x) +> (ZipList fs) <*> (ZipList xs) = ZipList (zipWith ($) fs xs) + +
+ +> instance Functor ZipList where +> fmap f (ZipList xs) = ZipList (fmap f xs) + +
+ +Applicative +=========== + +> instance Applicative Identity where +> pure = Identity +> (Identity f) <*> (Identity x) = Identity (f x) + +* The __`Const`__ instance will be very, very important for lenses + +* Remember that you need the constraint __`Monoid m`__ + +> instance Monoid m => Applicative (Const m) where +> pure _ = Const mempty +> (Const x) <*> (Const y) = Const (x <> y) + +Applicative +=========== + +* The Monoidal formulation provides a clearer view of how applicative manipulates functorial contexts. + +* There are deep theoretical reasons behind the name "monoidal". + +> class Functor f => Monoidal f where +> unit :: f () +> (*&*) :: f a -> f b -> f (a,b) + +Laws +---- + +```haskell +fmap snd $ unit *&* v = v -- Left identity +fmap fst $ u *&* unit = u -- Right identity +fmap asl $ u *&* (v *&* w) = (u *&* v) *&* w -- Associativity +-- asl (x, (y, z)) = ((x, y), z) +``` + +* `fst`, `snd` and `asl` are needed because monoidal properties hold __upto isomorphism__. + +Applicative +=========== + +* Contexts somtimes represent some `impure` computations: + + - __Maybe a__: computation of type a which may fail + + - __[a]__: nondeterministic computations of type a + +```haskell +ghci> (+) <$> [1, 2, 3] <*> [10, 20] = [11,21,12,22,13,23] +ghci> (+) <$> [1, 2, 3] <*> [] = [] +ghci> (+) <$> Just 1 <*> Just 2 = Just 3 +ghci> (+) <$> Nothing <*> Just 2 = Nothing +``` + +* As you can see in the list example, __effects are sequenced from left to right__ (see implementation) + +* For __commutative applicative functors__ (e.g `Maybe`) this does not matter because they satisfy: + +```haskell +f <$> u <*> v = flip f <$> v <*> u +``` + +Applicative +=========== + +* As we have ssen with lists, the convention in Haskell is to always implement `(<*>)` and other applicative operators using __left-to-right sequencing__ + +* Commutativity (or the lack thereof) affects other functions which are derived from `(<*>)` as well. + +> -- Sequence actions, discarding the value of the first argument +> (*>) :: Applicative f => f a -> f b -> f b +> a1 *> a2 = (id <$ a1) <*> a2 + +> -- Sequence actions, discarding the value of the second argument +> (<*) :: Applicative f => f a -> f b -> f a +> (<*) = liftA2 const + +* The definition of `(*>)` uses this operator for functors + +> -- Replace all locations in the input with the same value +> (<$) :: Functor f => a -> f b -> f a +> (<$) = fmap . const + +Applicative +=========== + +* For commutative aplicatives swapping the arguments does not affect the __effects__ (that is, the being and nothingness of wrapped values) + +```haskell +ghci> Just 2 *> Just 3 +Just 3 +ghci> Just 3 *> Just 2 +Just 2 +ghci> Just 2 *> Nothing +Nothing +ghci> Nothing *> Just 2 +Nothing +``` + +* For `IO`, however, swapping the arguments does reorder the effects: + +```haskell +ghci> (print "foo" *> pure 2) *> (print "bar" *> pure 3) +"foo" +"bar" +3 +ghci> (print "bar" *> pure 3) *> (print "foo" *> pure 2) +"bar" +"foo" +2 +``` + +Applicative +=========== + +* For the same reason, `<**>` is not just `flip <*>` + +> (<**>) :: Applicative f => f a -> f (a -> b) -> f b +> (<**>) = liftA2 (\a f -> f a) + +```haskell +ghci> [(2*),(3*)] <*> [4,5] +[8,10,12,15] +ghci> (flip (<*>)) [4,5] [(2*),(3*)] +[8,10,12,15] +ghci> [4,5] <**> [(2*),(3*)] +[8,12,10,15] +``` + +* So in applicative effects __order can matter__ because computacions are __sequenced__ + +* It is no longer the __perfect world of pure functions__ + +* __Be careful__ because type signatures don't give all the information you may need !!! + Foldable ========