Top Banner
July 2015 @filippovitale Send + More = Money Let’s merge 2 monads to solve a simple “constraint satisfaction problem”
102

Send + More = Money – Let’s mash 2 monads to solve a simple CSP

Aug 14, 2015

Download

Software

Filippo Vitale
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

July 2015

@filippovitale

Send + More = MoneyLet’s merge 2 monads to solve a simple

“constraint satisfaction problem”

Page 2: Send + More = Money – Let’s mash 2 monads to solve a simple CSP
Page 3: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

We’re hiring!

Page 4: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

@alexeyraga

Page 5: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

SEND+ MORE------- MONEY

@alexeyraga

Page 6: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

SEND+ MORE------- MONEY

@alexeyraga

Page 7: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

SEND+ MORE------- MONEY

@alexeyraga

Page 8: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

SEND+ MORE------- MONEY

Page 9: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

SEND+ MORE------- MONEY

Page 10: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

SEND+ MORE------- MONEY

M←1

Page 11: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

SEND+ MORE------- MONEY

M←1

Page 12: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

SEND+ MORE------- MONEY

M←1

Page 13: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

SEND+ 1ORE------- 1ONEY

M←1

O←0S←8,9

Page 14: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

M←1Hold on a sec…

@alexeyraga

Page 15: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

M←1Programmatically!

@alexeyraga

Page 16: Send + More = Money – Let’s mash 2 monads to solve a simple CSP
Page 17: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

Immutability

Higher-ord

er

function Monad

Referentia

l

transparen

cy

Page 18: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

Mon*d

Page 19: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

Why Monads- Higher order control structures- Monads : loops = loops : gotos- Declarative vs. Imperative- Reusable ⊛ Composable ⊛ Factorisable- Easily parallelisable

Page 20: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

Brute force

10!/(10 – 8)!≈ 2 Million

How big is the search space?

Page 21: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

Brute ForceNaïve implementation

Page 22: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

for { s <- 0 to 9 if s != 0 e <- 0 to 9 if e != s n <- 0 to 9 if n != s && n != e d <- 0 to 9 if d != s && d != e && d!=n ...

for (int s = 0; s < 10; ++s) for (int e = 0; e < 10; ++e) for (int n = 0; n < 10; ++n) for (int d = 0; d < 10; ++d) ...

s != 0e != sn != s && n != ed != s && d != e && d != n

The solution boils down to:➔ generating all those substitutions➔ testing the constraints for each one

Page 23: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

val listOfDigits = (0 to 9).toList

val solutions = for { s <- listOfDigits if s != 0 e <- listOfDigits if s != e n <- listOfDigits if s != n && e != n d <- listOfDigits if s != d && e != d && n != d m <- listOfDigits if m != 0 if s != m && e != m && n != m && d != m o <- listOfDigits if s != o && e != o && n != o && d != o && m != o r <- listOfDigits if s != r && e != r && n != r && d != r && m != r && o != r y <- listOfDigits if s != y && e != y && n != y && d != y && m != y && o != y && r != y

send = List(s, e, n, d).reduce(_ * 10 + _) more = List(m, o, r, e).reduce(_ * 10 + _) money = List(m, o, n, e, y).reduce(_ * 10 + _) if send + more == money} yield (send, more, money)

Search candidate solutions

Constraintssatisfied?

Page 24: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

val listOfDigits = (0 to 9).toList

val solutions = for { s <- listOfDigits if s != 0 e <- listOfDigits if s != e n <- listOfDigits if s != n && e != n d <- listOfDigits if s != d && e != d && n != d m <- listOfDigits if m != 0 if s != m && e != m && n != m && d != m o <- listOfDigits if s != o && e != o && n != o && d != o && m != o r <- listOfDigits if s != r && e != r && n != r && d != r && m != r && o != r y <- listOfDigits if s != y && e != y && n != y && d != y && m != y && o != y && r != y

send = List(s, e, n, d).reduce(_ * 10 + _) more = List(m, o, r, e).reduce(_ * 10 + _) money = List(m, o, n, e, y).reduce(_ * 10 + _) if send + more == money} yield (send, more, money)

Page 25: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

“Jimmy” and theMulti-verse

Page 26: Send + More = Money – Let’s mash 2 monads to solve a simple CSP
Page 27: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

0 1 2 3

4 5 6 7

8 9

Page 28: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

1 2 3

4 5 6 7

8 9

0

Page 29: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

? ? ?

? ? ? ?

? ?

?

S = …

Page 30: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

1 2 3

4 5 6 7

8 9

0

0

S = 0!

Page 31: Send + More = Money – Let’s mash 2 monads to solve a simple CSP
Page 32: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

? ? ?

? ? ? ?

? ?

?

S = …

Page 33: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

0

1 2 3

4 5 6 7

8 9

0

1

2 3

4 5 6 7

8 9

0 1

2

3

4 5 6 7

8 9

5

1 2 3

4

0

6 7

8 9

0

6

2 3

4 5

1

7

8 9

0 1

7

3

4 5 6

2

8 9

0 1

3

2

4 5 6 7

8 9

0 1

8

3

4 5 6 7

8

9

0 1

4

32

5 6 7

8 9

0 1

9

3

4 5 6 7

8

2

Page 34: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

0

1 2 3

4 5 6 7

8 9

0

1

2 3

4 5 6 7

8 9

0 1

2

3

4 5 6 7

8 9

5

1 2 3

4

0

6 7

8 9

0

6

2 3

4 5

1

7

8 9

0 1

7

3

4 5 6

2

8 9

0 1

3

2

4 5 6 7

8 9

0 1

8

3

4 5 6 7

8

9

0 1

4

32

5 6 7

8 9

0 1

9

3

4 5 6 7

8

2

S = 1

Page 35: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

0

1

2 3

4 5 6 7

8 9

S = 1

Page 36: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

0

1

2 3

4 5 6 7

8 9

S = 1E = …

Page 37: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

0

1

2 3

4 5 6 7

8 9

S = 1E = …

0

2

3

4

5

6

789

Page 38: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

“What would Tony Morris do?”

Page 39: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

Multi-verse Implementation

using the State Monad

Page 40: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

“The future is a function of the past.”– A. P. Robertson

Page 41: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

// stateful computation

type State[S, +A] = S => (S, A)

Page 42: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

trait State[S, +A] { def eval(initial: S): A def map[B](f: A => B): State[S, B] def flatMap[B](f: A => State[S, B]): State[S, B]}

object State { def apply[S, A](f: S => (S, A)): State[S, A]}

Page 43: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

// stateful computation

f: S => (S, A)

def select(xs: List[Int]): (List[Int], Int) = (xs.tail, xs.head)

Page 44: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

// stateful computation

f: S => (S, A)

def select(xs: List[Int]): (List[Int], Int) = (xs.tail, xs.head)

Page 45: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

// stateful computation

f: S => (S, A)

def select(xs: List[Int]): (List[Int], Int) = (xs.tail, xs.head)

Page 46: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

import scalaz.State

val s = for { a <- State(select) b <- State(select)} yield Map('a' -> a, 'b' -> b)

val s = ???

Page 47: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

import scalaz.State

val s = for { a <- State(select) b <- State(select)} yield Map('a' -> a, 'b' -> b)

val s: State[ S, A ] = ???

Page 48: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

import scalaz.State

val s = for { a <- State(select) b <- State(select)} yield Map('a' -> a, 'b' -> b)

val s: State[ List[Int], Map[Char, Int] ] = ???

Page 49: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

import scalaz.State

val s = for { a <- State(select) b <- State(select)} yield Map('a' -> a, 'b' -> b)

val s: State[ List[Int], Map[Char, Int] ] = ???

s.eval(List(1, 2))====

Map('a' -> 1, 'b' -> 2)

Page 50: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

import scalaz.State

val s = for { a <- State(select) b <- State(select)} yield Map('a' -> a, 'b' -> b)

val s: State[ List[Int], Map[Char, Int] ] = ???

s.eval(List(8, 3))====

Map('a' -> 8, 'b' -> 3)

Page 51: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

val s = for { a <- State(select) b <- State(select) c <- State(select)} yield Map('a' -> a, 'b' -> b, 'c' -> c)

s.eval(1 |-> 3)

====

Map('a' -> 1, 'b' -> 2, 'c' -> 3)

Page 52: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

val s = for { a <- State(select) b <- State(select) c <- State(select) d <- State(select)} yield Map('a' -> a, 'b' -> b, 'c' -> c, 'd' -> d)

s.eval(1 |-> 4)

====

Map('a' -> 1, 'b' -> 2, 'c' -> 3, 'd' -> 4)

Page 53: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

Multi-verse Implementation

using List

Page 54: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

val l = for { a <- List(1, 2) b <- List(1, 2)} yield Map('a' -> a, 'b' -> b)

val l = ???

Page 55: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

val l = for { a <- List(1, 2) b <- List(1, 2)} yield Map('a' -> a, 'b' -> b)

List(Map('a' -> 1, 'b' -> 1), Map('a' -> 1, 'b' -> 2), Map('a' -> 2, 'b' -> 1), Map('a' -> 2, 'b' -> 2))

Page 56: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

val l = for { a <- List(1, 2) b <- List(1, 2) if a != b} yield Map('a' -> a, 'b' -> b)

List(Map('a' -> 1, 'b' -> 2), Map('a' -> 2, 'b' -> 1))

Page 57: Send + More = Money – Let’s mash 2 monads to solve a simple CSP
Page 58: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

Multi-verse Implementation

using StateT[List, S, A]

Page 59: Send + More = Money – Let’s mash 2 monads to solve a simple CSP
Page 60: Send + More = Money – Let’s mash 2 monads to solve a simple CSP
Page 61: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

def select[A](xs: List[A]): (List[A], A)

State S => ( S , A)

Page 62: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

def select[A](xs: List[A]): (List[A], A)

State S => ( S , A)

def select[A](xs: List[A]): List[(List[A], A)]

StateT[F, S, A] S => F[( S , A)]

Page 63: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

def select[A](xs: List[A]): List[(List[A], A)] =

xs map { x => (xs.filterNot(_ == x), x) }

Page 64: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

0

1 2 3

4 5 6 7

8 9

0

1

2 3

4 5 6 7

8 9

0 1

2

3

4 5 6 7

8 9

5

1 2 3

4

0

6 7

8 9

0

6

2 3

4 5

1

7

8 9

0 1

7

3

4 5 6

2

8 9

0 1

3

2

4 5 6 7

8 9

0 1

8

3

4 5 6 7

8

9

0 1

4

32

5 6 7

8 9

0 1

9

3

4 5 6 7

8

2

Page 65: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

sl.eval(1 |-> 2)

==

???

import scalaz.StateTimport scalaz.std.list._

val sl = for { a <- StateT(select) b <- StateT(select)} yield Map('a' -> a, 'b' -> b)

Page 66: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

import scalaz.StateTimport scalaz.std.list._

val sl = for { a <- StateT(select) b <- StateT(select)} yield Map('a' -> a, 'b' -> b)

sl.eval(1 |-> 2)

==

List(Map('a' -> 1, 'b' -> 2), Map('a' -> 2, 'b' -> 1))

Page 67: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

val sel = StateT(select[Int])

for { s <- sel e <- sel n <- sel d <- sel m <- sel o <- sel r <- sel y <- sel …}

Page 68: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

val sel = StateT(select[Int])

for { s <- sel if s != 0 e <- sel n <- sel d <- sel m <- sel if s != 0 o <- sel r <- sel y <- sel …}

Page 69: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

val sel = StateT(select[Int])

for { s <- sel if s != 0 e <- sel n <- sel d <- sel m <- sel if s != 0 o <- sel r <- sel y <- sel …}

?

Page 70: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

Guards via MonadPlus

Page 71: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

Functor

Applicative

Monad

MonadPlus

Page 72: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

trait PlusEmpty[F[_]] {

def empty[A]: F[A]

// ...}

Page 73: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

class BooleanOps(self: Boolean) {// ...

def guard[M[_]] = new GuardPrevent[M] { def apply[A](a: => A) = b.pointOrEmpty[M, A](self)(a) }

// ...}

Page 74: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

class BooleanOps(self: Boolean) {// ...

def guard[M[_]] = new GuardPrevent[M] { def apply[A](a: => A) = b.pointOrEmpty[M, A](self)(a) }

// ...}

(implicit M: Applicative[M], M0: PlusEmpty[M])

Page 75: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

class BooleanOps(self: Boolean) {// ...

def guard[M[_]] = new GuardPrevent[M] { def apply[A](a: => A) = b.pointOrEmpty[M, A](self)(a) }

// ...}

def pointOrEmpty[M[_], A](cond: Boolean)(a: => A): M[A] = if (cond) M.point(a) else M0.empty

Page 76: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

class BooleanOps(self: Boolean) {// ...

def guard[M[_]] = new GuardPrevent[M] { def apply[A](a: => A) = b.pointOrEmpty[M, A](self)(a) }

// ...}

def pointOrEmpty[M[_], A](cond: Boolean)(a: => A): M[A] = if (cond) M.point(a) else M0.empty

Page 77: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

val g = for { a <- StateT(selectSL[Int]) b <- StateT(selectSL[Int]) c <- StateT(selectSL[Int])} yield Map('a' -> a, 'b' -> b, 'c' -> c)

g.eval(1 |-> 3)

List( Map(a -> 1, b -> 2, c -> 3), Map(a -> 1, b -> 3, c -> 2), Map(a -> 2, b -> 1, c -> 3), Map(a -> 2, b -> 3, c -> 1), Map(a -> 3, b -> 1, c -> 2), Map(a -> 3, b -> 2, c -> 1))

Page 78: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

type StateL[A] = StateT[List, List[Int], A]

val g = for { a <- StateT(selectSL[Int]) b <- StateT(selectSL[Int]) c <- StateT(selectSL[Int]) _ <-(a+b==c).guard[StateL](())} yield Map('a' -> a, 'b' -> b, 'c' -> c)

g.eval(1 |-> 3)

List( Map(a -> 1, b -> 2, c -> 3), Map(a -> 2, b -> 1, c -> 3),)

Page 79: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

type StateL[A] = StateT[List, List[Int], A]

val g = for { a <- StateT(selectSL[Int]) b <- StateT(selectSL[Int]) c <- StateT(selectSL[Int]) _ <-(a+b==c).guard[StateL](())} yield Map('a' -> a, 'b' -> b, 'c' -> c)

g.eval(1 |-> 3)

List( Map(a -> 1, b -> 2, c -> 3), Map(a -> 2, b -> 1, c -> 3),)

MonadPlusMonadPlus

Page 80: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

scala> monadPlus.laws[List].check+ monad plus.monad.applicative.apply.functor.invariantFunctor.identity: OK, passed 100 tests.+ monad plus.monad.applicative.apply.functor.invariantFunctor.composite: OK, passed 100 tests.+ monad plus.monad.applicative.apply.functor.identity: OK, passed 100 tests.+ monad plus.monad.applicative.apply.functor.composite: OK, passed 100 tests.+ monad plus.monad.applicative.apply.composition: OK, passed 100 tests.+ monad plus.monad.applicative.identity: OK, passed 100 tests.+ monad plus.monad.applicative.homomorphism: OK, passed 100 tests.+ monad plus.monad.applicative.interchange: OK, passed 100 tests.+ monad plus.monad.applicative.map consistent with ap: OK, passed 100 tests.+ monad plus.monad.bind.apply.functor.invariantFunctor.identity: OK, passed 100 tests.+ monad plus.monad.bind.apply.functor.invariantFunctor.composite: OK, passed 100 tests.+ monad plus.monad.bind.apply.functor.identity: OK, passed 100 tests.+ monad plus.monad.bind.apply.functor.composite: OK, passed 100 tests.+ monad plus.monad.bind.apply.composition: OK, passed 100 tests.+ monad plus.monad.bind.associativity: OK, passed 100 tests.+ monad plus.monad.bind.ap consistent with bind: OK, passed 100 tests.+ monad plus.monad.right identity: OK, passed 100 tests.+ monad plus.monad.left identity: OK, passed 100 tests.+ monad plus.plusEmpty.plus.semigroup.associative: OK, passed 100 tests.+ monad plus.plusEmpty.plus.associative: OK, passed 100 tests.+ monad plus.plusEmpty.monoid.semigroup.associative: OK, passed 100 tests.+ monad plus.plusEmpty.monoid.left identity: OK, passed 100 tests.+ monad plus.plusEmpty.monoid.right identity: OK, passed 100 tests.+ monad plus.plusEmpty.left plus identity: OK, passed 100 tests.+ monad plus.plusEmpty.right plus identity: OK, passed 100 tests.+ monad plus.empty map: OK, passed 100 tests.+ monad plus.left zero: OK, passed 100 tests.

Page 81: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

type StateL[A] = StateT[List, List[Int], A]

val g = for { a <- StateT(selectSL[Int]) b <- StateT(selectSL[Int]) c <- StateT(selectSL[Int]) _ <-(a+b==c).guard[StateL](()) _ <- (a>b).prevent[StateL](())} yield Map('a' -> a, 'b' -> b, 'c' -> c)

g.eval(1 |-> 3)

List( Map(a -> 1, b -> 2, c -> 3),)

Page 82: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

type StateL[A] = StateT[List, List[Int], A]

val g = for { a <- StateT(selectSL[Int]) b <- StateT(selectSL[Int]) c <- StateT(selectSL[Int]) _ <-(a+b==c).guard[StateL](()) _ <- (a>b).prevent[StateL](())} yield Map('a' -> a, 'b' -> b, 'c' -> c)

g.eval(1 |-> 3)

List( Map(a -> 1, b -> 2, c -> 3),)

flatMap

Page 83: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

The FinalImplementation

Page 84: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

type StateL[A] = StateT[List, List[Int], A]

def solutions: StateL[(Int, Int, Int)] = ???

solutions.eval(0 |-> 9).head |> println

Page 85: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

type StateL[A] = StateT[List, List[Int], A]

def select[A](xs: List[A]): List[(List[A], A)] = xs map { x => (xs.filterNot(_ == x), x) }

def go(chars: List[Char], subst: Map[Char, Int])(i: Int): StateL[(Int, Int, Int)] = ???

def solutions: StateL[(Int, Int, Int)] = StateT(select[Int]) >>= go("sendmoremoney".toList.distinct, Map.empty)

solutions.eval(0 |-> 9).head |> println

Page 86: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

type StateL[A] = StateT[List, List[Int], A]

def select[A](xs: List[A]): List[(List[A], A)] = xs map { x => (xs.filterNot(_ == x), x) }

def go(chars: List[Char], subst: Map[Char, Int])(i: Int): StateL[(Int, Int, Int)] = chars match { case c :: Nil => prune(subst + (c -> i)) case c :: cs => StateT(select[Int]) >>= go(cs, subst + (c -> i)) }

def prune(charToDigit: Map[Char, Int]): StateL[(Int, Int, Int)] = ???

def solutions: StateL[(Int, Int, Int)] = StateT(select[Int]) >>= go("sendmoremoney".toList.distinct, Map.empty)

solutions.eval(0 |-> 9).head |> println

Page 87: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

type StateL[A] = StateT[List, List[Int], A]

def select[A](xs: List[A]): List[(List[A], A)] = xs map { x => (xs.filterNot(_ == x), x) }

def go(chars: List[Char], subst: Map[Char, Int])(i: Int): StateL[(Int, Int, Int)] = chars match { case c :: Nil => prune(subst + (c -> i)) case c :: cs => StateT(select[Int]) >>= go(cs, subst + (c -> i)) }

def prune(charToDigit: Map[Char, Int]): StateL[(Int, Int, Int)] = for { _ <- (charToDigit('m') == 0).prevent[StateL](()) _ <- (charToDigit('s') == 0).prevent[StateL](()) send = "send" map charToDigit reduce (_ * 10 + _) more = "more" map charToDigit reduce (_ * 10 + _) money = "money" map charToDigit reduce (_ * 10 + _) _ <- (send + more == money).guard[StateL](())} yield (send, more, money)

def solutions: StateL[(Int, Int, Int)] = StateT(select[Int]) >>= go("sendmoremoney".toList.distinct, Map.empty)

solutions.eval(0 |-> 9).head |> println

https://github.com/BartoszMilewski/MoreMoney/blob/master/Scala/src/main/scala/SendMoreMoney.scala

Page 88: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

select ::[a] ->[(a, [a])]select [] = []select(x:xs) = (x, xs) : [(y, x:ys) | (y, ys) <-select xs]

solve :: StateL [Int] (Int, Int, Int)solve = StateL select >>= go (nub "sendmoremoney") M.empty where go [c] subst i = prune (M.insert c i subst) go (c:cs) subst i = StateL select >>= go cs (M.insert c i subst) prune subst = do guard (get 's' /= 0 && get 'm' /= 0) let send = toNumber "send" more = toNumber "more" money = toNumber "money" guard $ send + more == money return (send, more, money) where get c = fromJust (M.lookup c subst) toNumber str = asNumber (map get str) asNumber = foldl (\t o -> t*10 + o) 0

main = print $ evalStateL solve [0..9]

https://github.com/BartoszMilewski/MoreMoney/blob/master/Haskell/Advanced.hs

Page 89: Send + More = Money – Let’s mash 2 monads to solve a simple CSP
Page 90: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

go [c] subst i = prune (M.insert c i subst)go (c:cs) subst i = StateL select >>= go cs (M.insert c i subst)

def go(chars: List[Char], subst: Map[Char, Int]) (i: Int) = chars match { case c :: Nil => prune(subst + (c -> i)) case c :: cs => StateT(select[Int]) >>= go(cs, subst + (c -> i))}

Page 91: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

def prune(charToDigit: Map[Char, Int]) = for { _ <- (charToDigit('m') == 0).prevent[StateL](()) _ <- (charToDigit('s') == 0).prevent[StateL](()) send = "send" map charToDigit reduce (_ * 10 + _) more = "more" map charToDigit reduce (_ * 10 + _) money = "money" map charToDigit reduce (_ * 10 + _) _ <- (send + more == money).guard[StateL](())} yield (send, more, money)

prune subst = do guard (get 's' /= 0 && get 'm' /= 0)

let send = toNumber "send" more = toNumber "more" money = toNumber "money" guard $ send + more == money return (send, more, money) where get c = fromJust (M.lookup c subst) toNumber str = asNumber (map get str) asNumber = foldl (\t o -> t*10 + o) 0

Page 92: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

What’s next?

Page 93: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

- “The Essence of the Iterator Pattern”- Parallel Execution- Different Algorithm- Parallel Genetic Algorithm - Solve it at compile time

What’s next?

FP-Syd

Page 94: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

- “The Essence of the Iterator Pattern”- Parallel Execution- Different Algorithm- Parallel Genetic Algorithm - Solve it at compile time

FP-Syd

scalaz.TraverseWhat’s next?

Page 95: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

- “The Essence of the Iterator Pattern”- Parallel Execution- Different Algorithm- Parallel Genetic Algorithm - Solve it at compile time

FP-Syd

scalaz.ApplicativePlusscalaz.Nondeterminism

What’s next?

Page 96: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

- “The Essence of the Iterator Pattern”- Parallel Execution- Different Algorithm- Parallel Genetic Algorithm - Solve it at compile time

FP-Syd(A + B % 10) = (C | 1C)

What’s next?

Page 97: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

- “The Essence of the Iterator Pattern”- Parallel Execution- Different Algorithm- Parallel Genetic Algorithm - Solve it at compile time

FP-SydCryptarithmetic problems

What’s next?

Page 98: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

- “The Essence of the Iterator Pattern”- Parallel Execution- Different Algorithm- Parallel Genetic Algorithm - Solve it at compile time

FP-SydPeano's arithmetic

Shapeless: HList, Sum, …

What’s next?

Page 99: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

- “The Essence of the Iterator Pattern”- Parallel Execution- Different Algorithm- Parallel Genetic Algorithm - Solve it at compile time

FP-Syd

What’s next?

Page 100: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

Resources- 4-part blog at http://BartoszMilewski.com- code: https://github.com/BartoszMilewski/MoreMoney- code: https://gist.github.com/filippovitale/6cc45396ed917a2a8411- Monad Transformers http://goo.gl/VhcJ65- State Monad https://goo.gl/jt6bvz- EIP http://www.cs.ox.ac.uk/jeremy.gibbons/publications/iterator.pdf- http://jto.github.io/articles/typelevel_quicksort/- Parallel Genetic Algorithm http://dl.acm.org/citation.cfm?id=1725467

Page 101: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

July 2015

@filippovitale

Thanks!

Page 102: Send + More = Money – Let’s mash 2 monads to solve a simple CSP

July 2015

@filippovitale

$ tail -f questions