Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Composition in FP

Composition in FP

Bucharest FP

August 20, 2018
Tweet

More Decks by Bucharest FP

Other Decks in Programming

Transcript

  1. Composition in FP
    Vladimir Ciobanu
    Monday, August 20, 2018

    View Slide

  2. Overview
    Algebraic Recap
    Back to FP
    Monad
    Applicative
    1

    View Slide

  3. Algebraic Recap

    View Slide

  4. What Is Composition?
    Composition is essential in functional programming. We use
    mathematical abstractions (such as Semigroup and Monoid)
    to define the composition of a wide variety of data types.
    Short recap:
    • Sets, e.g., B = { , ⊥}, N = {0, 1, 2, . . .},
    T = {Void, (), Bool, Int, ((), Bool), [(Int, Bool)], . . .}
    • Operations, e.g., there are four unary operations on
    Bool (const , const ⊥, identity and not)
    • Associativity, e.g., (a ∨ b) ∨ c = a ∨ (b ∨ c)
    • Commutativity, e.g., a ∨ b = b ∨ a
    2

    View Slide

  5. Semigroup
    A semigroup is an algebraic structure consisting of a set and
    an associative binary operation.
    Given a set S and an operation +, then:
    ∀ a, b ∈ S, ∃ c ∈ S, a + b = c
    ∀ a, b, c ∈ S, (a + b) + c = a + (b + c)
    Examples of semigroups: concatenation on (non-empty) lists,
    addition and multiplication of numbers, conjunction and
    disjunction of booleans, appending parts in a path or chunks
    of a file, combining IO actions, etc.
    3

    View Slide

  6. Monoid
    A monoid is an algebraic structure consisting of a set, an
    associative binary operation, and an identity element.
    Given a set S, an operation +, and the identity element e,
    then:
    ∀ a, b ∈ S, ∃ c ∈ S, a + b = c
    ∀ a, b, c ∈ S, (a + b) + c = a + (b + c)
    ∀ a ∈ S, e + a = a + e = a
    Examples of monoids: concatenation on (possibly empty)
    lists, addition and multiplication on numbers, conjunction and
    disjunction on booleans, appending parts in a path or chunks
    of a file, combining IO actions, etc.
    4

    View Slide

  7. Semiring 1/2
    A semiring is an algebraic structure consisting of a set S, a
    commutative monoid (S, +, 0) and monoid (S, ∗, 1), such that ∗
    distributes over + and 0 annihilates ∗.
    So, given a set S, and two operations + and ∗, and the identity
    elements 0 and 1, we can say:
    5

    View Slide

  8. Semiring 2/2
    ∀ a, b ∈ S, ∃ c ∈ S, a + b = c
    ∀ a, b, c ∈ S, (a + b) + c = a + (b + c)
    ∀ a ∈ S, 0 + a = a + 0 = a
    ∀ a, b ∈ S, a + b = b + a
    ∀ a, b ∈ S, ∃ c ∈ S, a ∗ b = c
    ∀ a, b, c ∈ S, (a ∗ b) ∗ c = a ∗ (b ∗ c)
    ∀ a ∈ S, 1 ∗ a = a ∗ 1 = a
    ∀ a, b, c ∈ S, a ∗ (b + c) = (a ∗ b) + (a ∗ c)
    ∀ a, b, c ∈ S, (a + b) ∗ c = (a ∗ c) + (b ∗ c)
    ∀ a ∈ S, a ∗ 0 = 0 ∗ a = 0 6

    View Slide

  9. Semiring Example: Bool
    ∀ a, b ∈ B, ∃ c ∈ B, a ∨ b = c
    ∀ a, b, c ∈ B, (a ∨ b) ∨ c = a ∨ (b ∨ c)
    ∀ a ∈ B, ⊥ ∨ a = a ∨ ⊥ = a
    ∀ a, b ∈ B, a ∨ b = b ∨ a
    ∀ a, b ∈ B, ∃ c ∈ B, a ∧ b = c
    ∀ a, b, c ∈ B, (a ∧ b) ∧ c = a ∧ (b ∧ c)
    ∀ a ∈ B, ∧ a = a ∧ = a
    ∀ a, b, c ∈ B, a ∧ (b ∨ c) = (a ∧ b) ∨ (a ∧ c)
    ∀ a, b, c ∈ B, (a ∨ b) ∧ c = (a ∧ c) ∨ (b ∧ c)
    ∀ a ∈ B, a ∧ ⊥ = ⊥ ∧ a = ⊥ 7

    View Slide

  10. Semiring Example: Types
    ∀ a, b ∈ T, ∃ c ∈ T, Either a b ∼
    = c
    ∀ a, b, c ∈ T, Either (Either a b) c ∼
    = Either a (Either b c)
    ∀ a ∈ T, Either Void a ∼
    = Either a Void ∼
    = a
    ∀ a, b ∈ T, Either a b ∼
    = Either b a
    ∀ a, b ∈ T, ∃ c ∈ T, (a, b) ∼
    = c
    ∀ a, b, c ∈ T, ((a, b), c) ∼
    = (a, (b, c))
    ∀ a ∈ T, ((), a) ∼
    = (a, ()) ∼
    = a
    ∀ a, b, c ∈ T, (a, Either b c) ∼
    = Either (a, b) (a, c)
    ∀ a, b, c ∈ T, ((Either a b), c) ∼
    = Either (a, c) (b, c)
    ∀ a ∈ T, (a, Void) ∼
    = (Void, a) ∼
    = Void 8

    View Slide

  11. Back to FP

    View Slide

  12. Monoid in Haskell
    1 class Semigroup a where
    2 (<>) :: a -> a -> a
    3
    4
    5 class Semigroup a => Monoid a where
    6 mempty :: a
    7
    8
    9 instance Semigroup [a] where
    10 a <> b = a ++ b
    11
    12
    13 instance Monoid [a] where
    14 mempty = []
    9

    View Slide

  13. Monoid Usage
    1 λ> "foo" <> "bar"
    2 "foobar"
    3
    4 fold :: (Foldable t, Monoid m) => t m -> m
    5 λ> fold ["fo", "o", "bar"]
    6 "foobar"
    7
    8 foldMap :: (Monoid m, Foldable t) => (a -> m) -> t a -> m
    9 λ> foldMap Sum [1,2,3,4,5]
    10 Sum {getSum = 15}
    11
    12 λ> foldMap All [True, True, True]
    13 All {getAll = True}
    14
    15 λ> foldMap All [True, True, False]
    16 All {getAll = False}
    10

    View Slide

  14. Combining Different Types
    11

    View Slide

  15. Monad

    View Slide

  16. Monad
    When viewed from the perspective of composability, monads
    allow us to compose things that are not obtained
    independently, but rather in a more sequential manner.
    1 conn 2 someData 3 writeToDisk someData
    4
    5 -- or:
    6 getSqlConnection
    7 >>= runSomeSelectQuery
    8 >>= writeToDisk
    12

    View Slide

  17. Just a Monoid in the...
    1 -- These two functions are equivalent:
    2 (>>=) :: m a -> (a -> m b) -> m b
    3 join :: m (m a) -> m a
    4
    5 -- Forward
    6 ma >>= mab = join (mab ma)
    7 -- Backward
    8 join mma = mma >>= id
    Any Monad is a Monoid. The easiest way to look at it is by
    looking at the join operation, which takes two m’s and returns
    a single m, or combines two m’s into a single one.
    See @KenScambler’s excellent tweets about this at
    https://twitter.com/KenScambler/status/956111889519357952
    13

    View Slide

  18. Applicative

    View Slide

  19. Applicative
    1 class Functor f where
    2 () :: (a -> b) -> f a -> f b
    3
    4 class Functor f => Applicative f where
    5 () :: f (a -> b) -> f a -> f b
    6 pure :: a -> f a
    7
    8 -- Applicative should really be like this.
    9 class Functor f => Apply f where
    10 () :: f (a -> b) -> f a -> f b
    11
    12 class Apply f => Applicative f where
    13 pure :: a -> f a
    14

    View Slide

  20. Applicative Example
    1 op :: A -> B -> C
    2 a :: A
    3 b :: B
    4
    5 op a b :: C
    6
    7 fa :: f A
    8 fb :: f B
    9
    10 op fa fb :: f C
    11
    12 λ> (+) Just 1 Just 2
    13 Just 3
    14
    15 λ> (+) Just 1 Nothing
    16 Nothing
    15

    View Slide

  21. Is this a semigroup / monoid?
    1 class Functor f => TupleSemigroup f where
    2 (<>) :: f a -> f b -> f (a, b)
    3
    4 class TupleSemigroup f => TupleMonoid f where
    5 mempty :: f ()
    The answer is, yes, if we alter the rules a bit to say that the
    operation is associative up to isomorphism (and that using
    the identity element results in isomorphic structures). The
    claim is these classes are equivalent to Apply and
    Applicative. How do we prove it? By implementing these in
    terms of Apply and Applicative, and then implementing
    Apply/Applicative in terms of these clases.
    16

    View Slide

  22. Equivalence
    1 -- Applicative -> Tuple*
    2 instance Apply f => TupleSemigroup f where
    3 (<>) :: f a -> f b -> f (a, b)
    4 fa <> fb = (,) fa fb
    5
    6 instance Applicative f => TupleMonoid where
    7 mempty :: f ()
    8 mempty = pure ()
    9
    10 -- Tuple* -> Applicative
    11 instance TupleSemigroup f => Apply f where
    12 () :: f (a -> b) -> f a -> f b
    13 fa2b fa = (\(a2b, a) -> a2b a) (fa2b <> fa)
    14
    15 instance TupleMonoid f => Applicative f where
    16 pure :: a -> f a
    17 pure a = const a mempty
    17

    View Slide

  23. Wait, is TupleMonoid really a Monoid?
    ∀ fa, fb ∈ T, ∃ fc ∈ T, fa <> fb ∼
    = fc ∼
    = f(a, b)
    ∀ fa, fb, fc ∈ T, (fa <> fb) <> fc ∼
    = fa <> (fb <> fc)
    f(a, b) <> fc ∼
    = fa <> f(b, c)
    f((a, b), c) ∼
    = f(a, (b, c))
    ∀ fa ∈ T, mempty <> fa ∼
    = fa <> mempty ∼
    = fa
    () <> fa ∼
    = fa <> () ∼
    = fa
    f(a, ()) ∼
    = f((), a) ∼
    = fa
    18

    View Slide

  24. Alternative
    1 -- Semigroup
    2 class Functor f => Alt f where
    3 () :: f a -> f a -> f a
    4
    5 -- Monoid
    6 class Alt f => class Plus f where
    7 empty :: f a
    8
    9 -- Near Semiring-ish
    10 class Applicative f, Plus f => Alternative f
    11
    12 -- Alternative guarantees the following laws:
    13 (f g) x == (f x) (g x)
    14 empty f == empty
    19

    View Slide

  25. Applicative Semiring Example
    1 λ> ([(+1), (+2)] [(+3), (+4)]) [1,2]
    2 [2,3,3,4,4,5,5,6]
    3
    4 λ> ([(+1), (+2)] [1,2]) ([(+3), (+4)] [1, 2])
    5 [2,3,3,4,4,5,5,6]
    6
    7 λ> [(+1), (+2)] empty
    8 []
    20

    View Slide

  26. Alternative Intuition
    To get some intuition, we can think of:
    • as: multiplication, conjunction, or carthesian product
    • pure as: 1, True, or the unit set
    • as: addition, disjunction, or concatenation
    • empty as: 0, False, or the empty set
    In a way, Applicative is a higher kinded monoid, and
    Alternative is a higher kinded semiring (except it’s not
    commutative in Plus).
    21

    View Slide

  27. Combining Different Types
    22

    View Slide

  28. Thank you for listening!
    cvlad
    vladciobanu
    cvlad.info
    23

    View Slide