Contravariant: The Other Side of the Coin George Wilson - - PowerPoint PPT Presentation

contravariant the other side of the coin
SMART_READER_LITE
LIVE PREVIEW

Contravariant: The Other Side of the Coin George Wilson - - PowerPoint PPT Presentation

Contravariant: The Other Side of the Coin George Wilson Data61/CSIRO george.wilson@data61.csiro.au 22nd May 2018 Contravariant newtype Predicate a = Predicate { runPredicate :: a -> Bool } newtype Predicate a = Predicate { runPredicate :: a


slide-1
SLIDE 1

Contravariant: The Other Side of the Coin

George Wilson

Data61/CSIRO george.wilson@data61.csiro.au

22nd May 2018

slide-2
SLIDE 2
slide-3
SLIDE 3

Contravariant

slide-4
SLIDE 4

newtype Predicate a = Predicate { runPredicate :: a -> Bool}

slide-5
SLIDE 5

newtype Predicate a = Predicate { runPredicate :: a -> Bool} evenP :: Predicate Int evenP = Predicate (\i -> i `mod` 2 == 0)

slide-6
SLIDE 6

newtype Predicate a = Predicate { runPredicate :: a -> Bool} evenP :: Predicate Int evenP = Predicate (\i -> i `mod` 2 == 0) x :: Bool x = runPredicate evenP 7

slide-7
SLIDE 7

gt5 :: Predicate Int gt5 = Predicate (\i -> i > 5)

slide-8
SLIDE 8

gt5 :: Predicate Int gt5 = Predicate (\i -> i > 5) lenGT5 :: Predicate String lenGT5 = Predicate (\str -> let i = length str in i > 5)

slide-9
SLIDE 9

gt5 :: Predicate Int gt5 = Predicate (\i -> i > 5) lenGT5 :: Predicate String lenGT5 = Predicate (\str -> let i = length str in i > 5) mapP :: (b -> a) -> Predicate a -> Predicate b mapP ba (Predicate abool) = Predicate (\b -> let a = ba b in abool a)

slide-10
SLIDE 10

gt5 :: Predicate Int gt5 = Predicate (\i -> i > 5) lenGT5' :: Predicate String lenGT5' = mapP length gt5 mapP :: (b -> a) -> Predicate a -> Predicate b mapP ba (Predicate abool) = Predicate (\b -> let a = ba b in abool a)

slide-11
SLIDE 11
slide-12
SLIDE 12
slide-13
SLIDE 13

Is Predicate a Functor?

slide-14
SLIDE 14

Is Predicate a Functor? mapP :: (b -> a) -> Predicate a -> Predicate b fmap :: (a -> b) -> Predicate a -> Predicate b

slide-15
SLIDE 15

[13, 74, 63, 12] :: List Int I contain Ints! You can access them if you'd like

slide-16
SLIDE 16

[13, 74, 63, 12] :: List Int I contain Ints! You can access them if you'd like even? Bool Int I am in need of an Int! :: Predicate Int

slide-17
SLIDE 17

class Contravariant f where contramap :: (b -> a) -> f a -> f b

slide-18
SLIDE 18

class Contravariant f where contramap :: (b -> a) -> f a -> f b Laws: contramap id = id contramap f . contramap g = contramap (g . f)

slide-19
SLIDE 19

class Contravariant f where contramap :: (b -> a) -> f a -> f b instance Contravariant Predicate where contramap :: (b -> a) -> Predicate a -> Predicate b contramap ba (Predicate abool) = Predicate (abool . ba)

slide-20
SLIDE 20

We need more power!

slide-21
SLIDE 21

class Functor f => Applicative f where (<*>) :: f (a -> b)

  • > f a -> f b

pure :: a -> f a

slide-22
SLIDE 22

class Functor f => ApplicativeL f where liftA2 :: ((a, b) -> c) -> f a -> f b -> f c pure :: a -> f a

slide-23
SLIDE 23

class Functor f => ApplicativeL f where liftA2 :: ((a, b) -> c) -> f a -> f b -> f c pure :: a -> f a (<*>) :: ApplicativeL f => f (a -> b) -> f a -> f b (<*>) fab fa = liftA2 (\(ab,a) -> ab a) fab fa

slide-24
SLIDE 24

class Contravariant f => Divisible f where divide :: (c -> (a, b)) -> f a -> f b -> f c conquer :: f a

slide-25
SLIDE 25

class Contravariant f => Divisible f where divide :: (c -> (a, b)) -> f a -> f b -> f c conquer :: f a

Laws: divide f m conquer = contramap (fst . f) m divide f conquer m = contramap (snd . f) m divide f (divide g m n) o = divide f' m (divide id n o) where f' a = case f a of (bc,d) -> case g bc of (b,c) -> (a,(b,c))

slide-26
SLIDE 26

class Contravariant f => Divisible f where divide :: (c -> (a, b)) -> f a -> f b -> f c conquer :: f a instance Divisible Predicate where divide cab (Predicate pa) (Predicate pb) = Predicate $ \c -> case cab c of (a,b) -> pa a && pb b conquer = Predicate (\_ -> True)

slide-27
SLIDE 27
slide-28
SLIDE 28

ingredients :: (Banana, IceCream)

slide-29
SLIDE 29

ingredients :: (Banana, IceCream) ripe :: Predicate Banana frozen :: Predicate IceCream

slide-30
SLIDE 30

ingredients :: (Banana, IceCream) ripe :: Predicate Banana frozen :: Predicate IceCream divide :: Divisible f => (c -> (a,b)) -> f a -> f b -> f c divide id :: Divisible f => f a -> f b -> f (a,b)

slide-31
SLIDE 31

ingredients :: (Banana, IceCream) ripe :: Predicate Banana frozen :: Predicate IceCream divide :: Divisible f => (c -> (a,b)) -> f a -> f b -> f c divide id :: Divisible f => f a -> f b -> f (a,b) divide id ripe frozen :: Predicate (Banana, IceCream)

slide-32
SLIDE 32

ingredients :: (Banana, IceCream) ripe :: Predicate Banana frozen :: Predicate IceCream divide :: Divisible f => (c -> (a,b)) -> f a -> f b -> f c divide id :: Divisible f => f a -> f b -> f (a,b) divide id ripe frozen :: Predicate (Banana, IceCream) runPredicate (divide id ripe frozen) ingredients :: Bool

slide-33
SLIDE 33

(Banana, IceCream) ripe frozen Bool Bool

&&

slide-34
SLIDE 34

data Kitchen = Kitchen Rice Curry Banana Apple IceCream

slide-35
SLIDE 35

data Kitchen = Kitchen Rice Curry Banana Apple IceCream ripe :: Predicate Banana frozen :: Predicate IceCream

slide-36
SLIDE 36

data Kitchen = Kitchen Rice Curry Banana Apple IceCream ripe :: Predicate Banana frozen :: Predicate IceCream getIngredients :: Kitchen -> (Banana, IceCream) getIngredients (Kitchen _ _ b _ i) = (b,i)

slide-37
SLIDE 37

data Kitchen = Kitchen Rice Curry Banana Apple IceCream ripe :: Predicate Banana frozen :: Predicate IceCream getIngredients :: Kitchen -> (Banana, IceCream) getIngredients (Kitchen _ _ b _ i) = (b,i) divide :: Divisible f => (c -> (a,b)) -> f a -> f b -> f c

slide-38
SLIDE 38

data Kitchen = Kitchen Rice Curry Banana Apple IceCream ripe :: Predicate Banana frozen :: Predicate IceCream getIngredients :: Kitchen -> (Banana, IceCream) getIngredients (Kitchen _ _ b _ i) = (b,i) divide :: Divisible f => (c -> (a,b)) -> f a -> f b -> f c divide getIngredients ripe frozen :: Predicate Kitchen

slide-39
SLIDE 39

(Banana, IceCream) ripe frozen Bool Bool

&&

Kitchen

slide-40
SLIDE 40
slide-41
SLIDE 41

What about Alternative?

slide-42
SLIDE 42

class Contravariant f => Divisible f where divide :: (c -> (a, b)) -> f a -> f b -> f c conquer :: f a

slide-43
SLIDE 43

class Contravariant f => Divisible f where divide :: (c -> (a, b)) -> f a -> f b -> f c conquer :: f a class Divisible f => Decidable f where choose :: (c -> Either a b) -> f a -> f b -> f c lose :: (a -> Void) -> f a

slide-44
SLIDE 44

data Void absurd :: Void -> a absurd v = case v of {}

slide-45
SLIDE 45

data Void absurd :: Void -> a absurd v = case v of {} left :: Either a Void -> a left = either id absurd right :: Either Void b -> b right = either absurd id

slide-46
SLIDE 46

class Divisible f => Decidable f where choose :: (c -> Either a b) -> f a -> f b -> f c lose :: (a -> Void) -> f a

slide-47
SLIDE 47

class Divisible f => Decidable f where choose :: (c -> Either a b) -> f a -> f b -> f c lose :: (a -> Void) -> f a

Laws: choose Left m (lose f) = m choose Right (lose f) m = m choose f (choose g m n) o = choose f' m (choose id n o) where f' bcd = either (either id (Right . Left) . g) (Right . Right) . f

slide-48
SLIDE 48

class Divisible f => Decidable f where choose :: (c -> Either a b) -> f a -> f b -> f c lose :: (a -> Void) -> f a instance Decidable Predicate where choose cab (Predicate pa) (Predicate pb) = Predicate $ \c -> case cab c of Left a -> pa a Right b -> pb b lose av = Predicate (\a -> absurd (av a))

slide-49
SLIDE 49

Predicates are boring

slide-50
SLIDE 50

newtype Printer a = Printer { runPrinter :: a -> String }

slide-51
SLIDE 51

string :: Printer String string = Printer id konst :: String -> Printer a konst s = Printer (const s) showP :: Show a => Printer a showP = Printer show int :: Printer Int int = showP newline :: Printer () newline = konst "\n"

slide-52
SLIDE 52

instance Contravariant Printer where contramap ba (Printer as) = Printer (as . ba)

slide-53
SLIDE 53

instance Contravariant Printer where contramap ba (Printer as) = Printer (as . ba) instance Divisible Printer where divide cab (Printer as) (Printer bs) = Printer $ \c -> case cab c of (a,b) -> as a <> bs b conquer = Printer (const "")

slide-54
SLIDE 54

instance Decidable Printer where choose cab (Printer as) (Printer bs) = Printer $ \c -> case cab c of Left a -> as a Right b -> bs b lose av = Printer (\a -> absurd (av a))

slide-55
SLIDE 55

(>$<) :: Contravariant f => (b -> a) -> f a -> f b (>$<) = contramap

slide-56
SLIDE 56

(>$<) :: Contravariant f => (b -> a) -> f a -> f b (>$<) = contramap (>*<) :: Divisible f => f a -> f b -> f (a,b) (>*<) = divide id

slide-57
SLIDE 57

(>$<) :: Contravariant f => (b -> a) -> f a -> f b (>$<) = contramap (>*<) :: Divisible f => f a -> f b -> f (a,b) (>*<) = divide id (>|<) :: Decidable f => f a -> f b -> f (Either a b) (>|<) = choose id

slide-58
SLIDE 58

(>$<) :: Contravariant f => (b -> a) -> f a -> f b (>$<) = contramap (>*<) :: Divisible f => f a -> f b -> f (a,b) (>*<) = divide id (>|<) :: Decidable f => f a -> f b -> f (Either a b) (>|<) = choose id (>*) :: Divisible f => f a -> f () -> f a (>*) = divide (\a -> (a,())) (*<) :: Divisible f => f () -> f a -> f a (*<) = divide (\a -> ((),a))

slide-59
SLIDE 59

infixr 3 >$< infixr 4 >*< infixr 3 >|< infixr 4 >* infixr 4 *<

slide-60
SLIDE 60

data Car = Car { make :: String , model :: String , engine :: Engine } data Engine = Pistons Int | Rocket

slide-61
SLIDE 61

data Car = Car { make :: String , model :: String , engine :: Engine } data Engine = Pistons Int | Rocket car :: Car car = Car "Toyota" "Corolla" (Pistons 4)

slide-62
SLIDE 62

engineToEither :: Engine -> Either Int () engineToEither e = case e of Pistons i -> Left i Rocket

  • > Right ()

enginePrint :: Printer Engine enginePrint = engineToEither >$< konst "Pistons: " *< int >|< konst "Rocket"

slide-63
SLIDE 63

carToTuple :: Car -> (String, (String, Engine)) carToTuple (Car ma mo e) = (ma, (mo, e)) carPrint :: Printer Car carPrint = carToTuple >$< (konst "Make: " *< string >* newline) >*< (konst "Model: " *< string >* newline) >*< enginePrint

slide-64
SLIDE 64

putStrLn $ runPrinter carPrint car

Make: Toyota Model: Corolla Pistons: 4

slide-65
SLIDE 65
  • Applicative and Alternative let us talk about how to

combine multiple results

  • Divisible and Decidable let us talk about how to

consume multiple inputs

slide-66
SLIDE 66

Thanks for listening! Questions?

slide-67
SLIDE 67

References

  • https://hackage.haskell.org/package/contravariant
  • https://github.com/qfpl/invariant-extras
  • https://hackage.haskell.org/package/generics-eot
  • Discrimination is Wrong

https://www.youtube.com/watch?v=eXDJ5Jcbgk8

slide-68
SLIDE 68

“Is there a contravariant Monad?” No

class Applicative f => MonadJ f where join :: f (f a) -> f a but newtype Compose f g a = Compose (f (g a)) instance (Contravariant f, Contravariant g) => Functor (Compose f g) where fmap z (Compose fga) = Compose $ contramap (contramap z) fga

slide-69
SLIDE 69

“Is anything both contravariant and covariant?”

data Const c a = Const c instance Functor (Const c) where fmap f (Const c) = Const c instance Contravariant (Const c) where contramap f (Const c) = Const c Every a is in positive position Every a is in negative position