Upload
filippo-vitale
View
16
Download
2
Embed Size (px)
Citation preview
July 2015
@filippovitale
Send + More = MoneyLet’s merge 2 monads to solve a simple
“constraint satisfaction problem”
Why Monads- Higher order control structures- Monads : loops = loops : gotos- Declarative vs. Imperative- Reusable ⊛ Composable ⊛ Factorisable- Easily parallelisable
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
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?
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)
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
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
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]}
// stateful computation
f: S => (S, A)
def select(xs: List[Int]): (List[Int], Int) = (xs.tail, xs.head)
// stateful computation
f: S => (S, A)
def select(xs: List[Int]): (List[Int], Int) = (xs.tail, xs.head)
// stateful computation
f: S => (S, A)
def select(xs: List[Int]): (List[Int], Int) = (xs.tail, xs.head)
import scalaz.State
val s = for { a <- State(select) b <- State(select)} yield Map('a' -> a, 'b' -> b)
val s = ???
import scalaz.State
val s = for { a <- State(select) b <- State(select)} yield Map('a' -> a, 'b' -> b)
val s: State[ S, A ] = ???
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] ] = ???
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)
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)
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)
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)
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))
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))
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)]
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
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)
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))
val sel = StateT(select[Int])
for { s <- sel e <- sel n <- sel d <- sel m <- sel o <- sel r <- sel y <- sel …}
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 …}
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 …}
?
class BooleanOps(self: Boolean) {// ...
def guard[M[_]] = new GuardPrevent[M] { def apply[A](a: => A) = b.pointOrEmpty[M, A](self)(a) }
// ...}
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])
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
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
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))
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),)
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
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.
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),)
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
type StateL[A] = StateT[List, List[Int], A]
def solutions: StateL[(Int, Int, Int)] = ???
solutions.eval(0 |-> 9).head |> println
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
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
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
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
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))}
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
- “The Essence of the Iterator Pattern”- Parallel Execution- Different Algorithm- Parallel Genetic Algorithm - Solve it at compile time
What’s next?
FP-Syd
- “The Essence of the Iterator Pattern”- Parallel Execution- Different Algorithm- Parallel Genetic Algorithm - Solve it at compile time
FP-Syd
scalaz.TraverseWhat’s next?
- “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?
- “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?
- “The Essence of the Iterator Pattern”- Parallel Execution- Different Algorithm- Parallel Genetic Algorithm - Solve it at compile time
FP-SydCryptarithmetic problems
What’s next?
- “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?
- “The Essence of the Iterator Pattern”- Parallel Execution- Different Algorithm- Parallel Genetic Algorithm - Solve it at compile time
FP-Syd
What’s next?
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