SlideShare a Scribd company logo
1 of 58
Download to read offline
Monadologie —
  professional help for
          type anxiety

              Christopher League
              12 July 2010
Monadologie —
github.com/league/scala-type-anxiety




                @chrisleague
          league@contrapunctus.net
1996
Principles of
Programming
Languages


January 1997 § Paris
“Java might be the vehicle    Principles of
 that will help us carry      Programming
 modern programming
 language innovations         Languages
 into industrial practice.”
              – me
                              January 1997 § Paris
Scala
Monadologie
   continuations
         monads
     existentials
        variance
           effects
Monadologie
   continuations – control flow
         monads – data flow
Continuations
Continuation-
Passing
Style
def plus [A] (x: Int, y: Int, k: Int=>A): A =
    k(x+y)

def times [A] (x: Int, y: Int, k: Int=>A): A =
    k(x*y)

def less [A] (x: Int, y: Int,
              kt: => A, kf: => A): A =
    if(x < y) kt else kf
def factorial [A] (n: Int, k: Int => A): A =
    less(n, 2, k(1),
         plus(n, -1, (m:Int) =>
              factorial(m, (f:Int) =>
                        times(n, f, k))))


scala>   factorial(5, println)
120
scala>   factorial(3, factorial(_, println))
720
scala>   val n = factorial(3, r => r)
n: Int   = 6
CPS
makes some programs simpler
class Regex
case class Literal(s: String)    extends       Regex
case class Concat(r1: Regex, r2: Regex)
                                 extends       Regex
case class Choice(r1: Regex, r2: Regex)
                                 extends       Regex
case class Star(r: Regex)        extends       Regex

Concat(Star(Literal("ab")), Literal("abc"))
// (ab*)abc matches abababc

Choice(Star(Literal("ab")),
       Concat(Literal("a"), Star(Literal("ba"))))
// (ab)*|a(ba)* matches abababa
def accept (regex: Regex, chars: Seq[Char],
            k: Seq[Char] => Boolean): Boolean =
  regex match {
    case Literal(expect) =>
      if(chars.take(expect.length).sameElements(expect))
        k(chars.drop(expect.length))
      else false
    case Concat(regex1, regex2) =>
      accept(regex1, chars, remaining =>
        accept(regex2, remaining, k))
    case Choice(regex1, regex2) =>
      accept(regex1, chars, k) || accept(regex2, chars, k)
    case Star(repeatable) =>
      k(chars) ||
      accept(repeatable, chars, remaining =>
        accept(regex, remaining, k))
  }
def accept (regex: Regex, chars: Seq[Char],
            k: Seq[Char] => Boolean): Boolean =
  ...

def complete (remaining: Seq[Char]): Boolean =
    remaining.length == 0

accept(regex1, "abababc", complete) // true
accept(regex2, "abababa", complete) // true
accept(regex1, "abababcd", complete) // false
Delimited
Continuations
via compiler plugin (2.8)
Delimited
Continuations
    shift & reset
def doSomething0 = reset {
  println("Ready?")
  val result = 1 + special * 3
  println(result)
}


        Punch a hole in your code.
        What type of value is expected in the hole?
        What happens after the hole?
        What is result type of the reset block?
def doSomething0 = reset {
  println("Ready?")
  val result = 1 + special * 3
  println(result)
}


        Think of the rest of the computation as
        a function with the hole as its parameter.
        Call it the continuation.
def doSomething1 = reset {
  println("Ready?")
  val result = 1 + special * 3
  println(result)
}

def special = shift {
  k: (Int => Unit) =>
    println(99)
    "Gotcha!"     shift captures the continuation and
}                 then determines its own future.
def doSomething1 = reset {
  println("Ready?")
  val result = 1 + special * 3
  println(result)
}

def special = shift {
  k: (Int => Unit) =>
    println(99)
    "Gotcha!"     shift doSomething1
                scala> captures the continuation and
}               Ready?determines its own future.
                  then
                   99
                   res0: java.lang.String = Gotcha!
def doSomething2 = reset {
  println("Ready?")
  val result = 1 + wacky * 3
  println(result)
}

def wacky = shift {
  k: (Int => Unit) =>
    k(2)
    println("Yo!")
    k(3)
}
def doSomething2 = reset {
  println("Ready?")
  val result = 1 + wacky * 3
  println(result)
}

def wacky = shift {
  k: (Int => Unit) =>
    k(2)
    println("Yo!")    scala> doSomething2
    k(3)              Ready?
}                     7
                       Yo!
                       10
Continuation
low-level control-flow primitive that
can implement:
                exceptions
                concurrency (actors)
                suspensions (lazy)
                …
def multi = reset {
  println("This function returns tentatively")
  println("but you can always ask for more.")
  produce(42)
  println("Didn't like that? Back again.")
  produce(99)
  println("Still not OK? I'm out of ideas!")
  None
}
def multi = reset {
  println("This function returns tentatively")
  println("but you can always ask for more.")
  produce(42)
  println("Didn't like that? Back again.")
          scala> multi
  produce(99) function returns tentatively
          This
  println("Still can alwaysI'm out more.
          but you not OK? ask for of ideas!")
  None    res0: Option[ReturnThunk[Int]] = Some(...)
}         scala> println(res0.get.value)
          42
          scala> res0.get.proceed
          Didn’t like that? Back again.
          res1: Option[ReturnThunk[Int]] = Some(...)
          scala> println(res1.get.value)
          99
          scala> res1.get.proceed
          Still not OK? I’m out of ideas!
          res2: Option[ReturnThunk[Int]] = None
def multi = reset {
  println("This function returns tentatively")
  println("but you can always ask for more.")
  produce(42)
  println("Didn't like that? Back again.")
  produce(99)
  println("Still not OK? I'm out of ideas!")
  None
}
case class ReturnThunk[A]
  (value: A,
   proceed: Unit => Option[ReturnThunk[A]])

def produce [A] (value: A):
    Unit @cps[Option[ReturnThunk[A]]] =
  shift {
    k: (Unit => Option[ReturnThunk[A]]) =>
      Some(ReturnThunk(value, k))
  }
def multi = reset {
  println("This function returns tentatively")
  println("but you can always ask for more.")
  produce(42)
  println("Didn't like that? Back again.")
  produce(99)
  println("Still not OK? I'm out of ideas!")
  None
}
def interact = reset {
  val first = ask("Please give me a number")
  val second = ask("Enter another number")
  printf("The sum of your numbers is: %dn",
         first + second)
}
def interact = reset {
  val first = ask("Please give me a number")
  val second = ask("Enter another number")
  printf("The sum of your numbers is: %dn",
         first + second)
}
    scala> interact
    Please give me a number
    respond with: submit(0x28d092b7, ...)
    scala> submit(0x28d092b7, 14)
    Enter another number
    respond with: submit(0x1ddb017b, ...)
    scala> submit(0x1ddb017b, 28)
    The sum of your numbers is: 42
type UUID = Int
def uuidGen: UUID = Random.nextInt
type Data = Int
val sessions = new HashMap[UUID, Data=>Unit]

def ask(prompt: String): Data @cps[Unit] = shift {
    k: (Data => Unit) => {
      val id = uuidGen
      printf("%snrespond with: submit(0x%x, ...)n",
             prompt, id)
      sessions += id -> k
    }
}

def submit(id: UUID, data: Data) = sessions(id)(data)

def interact = reset {
  val first = ask("Please give me a number")
  val second = ask("Enter another number")
  printf("The sum of your numbers is: %dn",
         first + second)
}
HARMFUL
def harmful = reset {
    var i = 0
    println("Hello world!")
    label("loop")
    println(i)
    i = i + 1
    if(i < 20) goto("loop")
    println("Done.")
}
def harmful = reset {
    var i = 0
    println("Hello world!")   Hello world!
    label("loop")             0
    println(i)                1
    i = i + 1                 2
                              .
    if(i < 20) goto("loop")   .
    println("Done.")          .
}                             18
                              19
                              Done.
def harmful = reset {
    var i = 0
    println("Hello world!")
    label("loop")
    println(i)
    i = i + 1
    if(i < 20) goto("loop")
    println("Done.")
}
val labelMap = new HashMap[String, Unit=>Unit]

def label(name:String) =
  shift { k:(Unit=>Unit) =>
    labelMap += name -> k
    k()
  }
def goto(name:String) =
  shift { k:(Unit=>Unit) => labelMap(name)() }
def harmful = reset {
    var i = 0
    println("Hello world!")
    label("loop")
    println(i)
    i = i + 1
    if(i < 20) goto("loop")
    println("Done.")
}
Monads
the leading design pattern
for functional programming
A type constructor M is a monad
if it supports these operations:
 def unit[A] (x: A): M[A]

 def flatMap[A,B] (m: M[A]) (f: A => M[B]): M[B]

 def map[A,B] (m: M[A]) (f: A => B): M[B] =
   flatMap(m){ x => unit(f(x)) }

 def andThen[A,B] (ma: M[A]) (mb: M[B]): M[B] =
   flatMap(ma){ x => mb }
Option is a monad.
def unit[A] (x: A): Option[A] = Some(x)

def flatMap[A,B](m:Option[A])(f:A =>Option[B]):
    Option[B] =
  m match {
    case None => None
    case Some(x) => f(x)
  }
List is a monad.
def unit[A] (x: A): List[A] = List(x)

def flatMap[A,B](m:List[A])(f:A =>List[B]): List[B] =
  m match {
    case Nil => Nil
    case x::xs => f(x) ::: flatMap(xs)(f)
  }
For comprehension: convenient syntax for monadic structures.
            for(i    <- 1 to   4;
                j    <- 1 to   i;
                k    <- 1 to   j)
            yield    { i*j*k   }

Compiler translates it to:
         (1 to 4).flatMap { i =>
           (1 to i).flatMap { j =>
             (1 to j).map { k =>
               i*j*k }}}
Example: a series of operations, where each may fail.
 lookupVenue: String => Option[Venue]
 getLoggedInUser: SessionID => Option[User]
 reserveTable: (Venue, User) => Option[ConfNo]
Example: a series of operations, where each may fail.
 lookupVenue: String => Option[Venue]
 getLoggedInUser: SessionID => Option[User]
 reserveTable: (Venue, User) => Option[ConfNo]

 val user = getLoggedInUser(session)
 val confirm =
   if(!user.isDefined) { None }
   else lookupVenue(name) match {
     case None => None
     case Some(venue) => {
       val confno = reserveTable(venue, user.get)
       if(confno.isDefined)
         mailTo(confno.get, user.get)
       confno
     }
   }
Example: a series of operations, where each may fail.
 lookupVenue: String => Option[Venue]
 getLoggedInUser: SessionID => Option[User]
 reserveTable: (Venue, User) => Option[ConfNo]

 val user = getLoggedInUser(session)
 val confirm =
   if(!user.isDefined) { None }
   else lookupVenue(name) match {
     case None => None
     case Some(venue) => {
       val confno = reserveTable(venue, user.get)
       if(confno.isDefined)
         mailTo(confno.get, user.get)
       confno
     }
   }
Example: a series of operations, where each may fail.
 lookupVenue: String => Option[Venue]
 getLoggedInUser: SessionID => Option[User]
 reserveTable: (Venue, User) => Option[ConfNo]

 val confirm =
   for(venue <- lookupVenue(name);
       user <- getLoggedInUser(session);
       confno <- reserveTable(venue, user))
   yield {
     mailTo(confno, user)
     confno
   }
Example from Lift form validation:
  def addUser(): Box[UserInfo] =
    for {
      firstname <- S.param("firstname") ?~
                  "firstname parameter missing" ~> 400
      lastname <- S.param("lastname") ?~
                  "lastname parameter missing"
      email <- S.param("email") ?~
                  "email parameter missing"
    } yield {
      val u = User.create.firstName(firstname).
      lastName(lastname).email(email)

        S.param("password") foreach u.password.set

        u.saveMe
    }
Example: use monad to pass around state behind the scenes

 class Tree[A]
 case class Leaf[A](elem: A) extends Tree[A]
 case class Branch[A](left: Tree[A], right: Tree[A])
        extends Tree[A]

 inject(‘Q’,        )               =>


    f               a                    Q               c
        d                       b            f                       g

            e   c       h   g                    d   e       a   h
def inject[A] (root: Tree[A], cur: A): (Tree[A], A) =
    root match {
      case Leaf(old) => (Leaf(cur), old)
      case Branch(left, right) =>
        val (t1, last1) = inject(left, cur)
        val (t2, last2) = inject(right, last1)
        (Branch(t1,t2), last2)
    }
def inject[A] (root: Tree[A], cur: A): (Tree[A], A) =
    root match {
      case Leaf(old) => (Leaf(cur), old)
      case Branch(left, right) =>
        val (t1, last1) = inject(left, cur)
        val (t2, last2) = inject(right, last1)
        (Branch(t1,t2), last2)
    }
def injectST[A] (root: Tree[A]): ST[A, Tree[A]] =
    root match {
      case Leaf(old) =>
        for(cur <- init[A];
            u <- update[A](_ => old))
          yield Leaf(cur)
      case Branch(left, right) =>
        for(t1 <- injectST(left);
            t2 <- injectST(right))
          yield Branch(t1,t2)
    }
case class ST[S,A](exec: S => (S,A)) {
  def flatMap[B] (f: A => ST[S,B]): ST[S,B] =
    ST { s0 =>
      val (s1, a) = exec(s0)
      f(a).exec(s1)
      }

    def map[B] (f: A => B)
          (implicit unit: B => ST[S,B]) : ST[S,B] =
      flatMap { x => unit(f(x)) }
}

implicit def unitST[S,A] (x: A): ST[S,A] =
  ST { s0 => (s0, x) }

def init[S]: ST[S,S] =
  ST { s0 => (s0, s0) }

def update[S] (g: S => S): ST[S,Unit] =
  ST { s0 => (g(s0), ()) }
case class ST[S,A](exec: S => (S,A)) {
  def flatMap[B] (f: scala> ST[S,B]): ST[S,B] =
                     A => drawTree(t1,"")
    ST { s0 =>       ______f
                     | _____d
      val (s1, a) = exec(s0)
                     |     _____e
      f(a).exec(s1) |         __c
      }              _____a
                             ________h
                                | __g
    def map[B] (f: A =>     B) __b
          (implicit unit: B => ST[S,B]) : ST[S,B] =
      flatMap { x => unit(f(x)) m }= injectST(t1)
                       scala> val
                       m: ST[Char,Tree[Char]] = ST(<function1>)
}
                          scala> val (_,t2) = m.exec('Q')
                          t2: Tree[Char] = ...
implicit def unitST[S,A] (x: A): ST[S,A] =
  ST { s0 => (s0, x) scala> drawTree(t2,"")
                     }
                     ______Q
def init[S]: ST[S,S] | _____f
                     =
                     |      _____d
  ST { s0 => (s0, s0)| }       __e
                     _____c
                         ________a
def update[S] (g: S => S): ST[S,Unit]
                            | __h
                                                =
  ST { s0 => (g(s0), ()) }  __g
Monadologie
github.com/league/scala-type-anxiety




                @chrisleague
          league@contrapunctus.net

More Related Content

What's hot

深入浅出Jscex
深入浅出Jscex深入浅出Jscex
深入浅出Jscex
jeffz
 

What's hot (20)

[Codemotion 2015] patrones de diseño con java8
[Codemotion 2015] patrones de diseño con java8[Codemotion 2015] patrones de diseño con java8
[Codemotion 2015] patrones de diseño con java8
 
Hitchhiker's Guide to Functional Programming
Hitchhiker's Guide to Functional ProgrammingHitchhiker's Guide to Functional Programming
Hitchhiker's Guide to Functional Programming
 
Struct examples
Struct examplesStruct examples
Struct examples
 
The Ring programming language version 1.3 book - Part 25 of 88
The Ring programming language version 1.3 book - Part 25 of 88The Ring programming language version 1.3 book - Part 25 of 88
The Ring programming language version 1.3 book - Part 25 of 88
 
Oh Composable World!
Oh Composable World!Oh Composable World!
Oh Composable World!
 
Scala taxonomy
Scala taxonomyScala taxonomy
Scala taxonomy
 
Type classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritanceType classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritance
 
The Ring programming language version 1.7 book - Part 40 of 196
The Ring programming language version 1.7 book - Part 40 of 196The Ring programming language version 1.7 book - Part 40 of 196
The Ring programming language version 1.7 book - Part 40 of 196
 
The Ring programming language version 1.9 book - Part 41 of 210
The Ring programming language version 1.9 book - Part 41 of 210The Ring programming language version 1.9 book - Part 41 of 210
The Ring programming language version 1.9 book - Part 41 of 210
 
深入浅出Jscex
深入浅出Jscex深入浅出Jscex
深入浅出Jscex
 
Error Handling in Scala
Error Handling in ScalaError Handling in Scala
Error Handling in Scala
 
λ | Lenses
λ | Lensesλ | Lenses
λ | Lenses
 
The Ring programming language version 1.5.2 book - Part 32 of 181
The Ring programming language version 1.5.2 book - Part 32 of 181The Ring programming language version 1.5.2 book - Part 32 of 181
The Ring programming language version 1.5.2 book - Part 32 of 181
 
Tupple ware in scala
Tupple ware in scalaTupple ware in scala
Tupple ware in scala
 
The Ring programming language version 1.10 book - Part 43 of 212
The Ring programming language version 1.10 book - Part 43 of 212The Ring programming language version 1.10 book - Part 43 of 212
The Ring programming language version 1.10 book - Part 43 of 212
 
The Ring programming language version 1.2 book - Part 22 of 84
The Ring programming language version 1.2 book - Part 22 of 84The Ring programming language version 1.2 book - Part 22 of 84
The Ring programming language version 1.2 book - Part 22 of 84
 
Introduction to idris
Introduction to idrisIntroduction to idris
Introduction to idris
 
The Ring programming language version 1.3 book - Part 24 of 88
The Ring programming language version 1.3 book - Part 24 of 88The Ring programming language version 1.3 book - Part 24 of 88
The Ring programming language version 1.3 book - Part 24 of 88
 
Clojure: The Art of Abstraction
Clojure: The Art of AbstractionClojure: The Art of Abstraction
Clojure: The Art of Abstraction
 
Functional Scala 2020
Functional Scala 2020Functional Scala 2020
Functional Scala 2020
 

Similar to Monadologie

(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?
Tomasz Wrobel
 
TI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class FunctionsTI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class Functions
Eelco Visser
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
Introduction to Functional Programming with Scala
Introduction to Functional Programming with ScalaIntroduction to Functional Programming with Scala
Introduction to Functional Programming with Scala
pramode_ce
 
Scala - where objects and functions meet
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meet
Mario Fusco
 

Similar to Monadologie (20)

Scala Functional Patterns
Scala Functional PatternsScala Functional Patterns
Scala Functional Patterns
 
(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?
 
SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
 
TI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class FunctionsTI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class Functions
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015
 
Fp in scala part 2
Fp in scala part 2Fp in scala part 2
Fp in scala part 2
 
Introduction to Scala
Introduction to ScalaIntroduction to Scala
Introduction to Scala
 
From Java to Scala - advantages and possible risks
From Java to Scala - advantages and possible risksFrom Java to Scala - advantages and possible risks
From Java to Scala - advantages and possible risks
 
Go: It's Not Just For Google
Go: It's Not Just For GoogleGo: It's Not Just For Google
Go: It's Not Just For Google
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
 
Spark workshop
Spark workshopSpark workshop
Spark workshop
 
Concurrent Application Development using Scala
Concurrent Application Development using ScalaConcurrent Application Development using Scala
Concurrent Application Development using Scala
 
Introduction to Functional Programming with Scala
Introduction to Functional Programming with ScalaIntroduction to Functional Programming with Scala
Introduction to Functional Programming with Scala
 
Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014
 
Scala - where objects and functions meet
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meet
 
Functional programming ii
Functional programming iiFunctional programming ii
Functional programming ii
 

More from league (6)

On the Edge, 2013
On the Edge, 2013On the Edge, 2013
On the Edge, 2013
 
The Scala Programming Language
The Scala Programming LanguageThe Scala Programming Language
The Scala Programming Language
 
On the edge
On the edgeOn the edge
On the edge
 
Modular Module Systems
Modular Module SystemsModular Module Systems
Modular Module Systems
 
Programming Android
Programming AndroidProgramming Android
Programming Android
 
Futzing with actors (etc.)
Futzing with actors (etc.)Futzing with actors (etc.)
Futzing with actors (etc.)
 

Recently uploaded

Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 

Recently uploaded (20)

Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 

Monadologie

  • 1. Monadologie — professional help for type anxiety Christopher League 12 July 2010
  • 2. Monadologie — github.com/league/scala-type-anxiety @chrisleague league@contrapunctus.net
  • 4.
  • 5.
  • 7. “Java might be the vehicle Principles of that will help us carry Programming modern programming language innovations Languages into industrial practice.” – me January 1997 § Paris
  • 9. Monadologie continuations monads existentials variance effects
  • 10. Monadologie continuations – control flow monads – data flow
  • 11.
  • 12.
  • 15. def plus [A] (x: Int, y: Int, k: Int=>A): A = k(x+y) def times [A] (x: Int, y: Int, k: Int=>A): A = k(x*y) def less [A] (x: Int, y: Int, kt: => A, kf: => A): A = if(x < y) kt else kf
  • 16. def factorial [A] (n: Int, k: Int => A): A = less(n, 2, k(1), plus(n, -1, (m:Int) => factorial(m, (f:Int) => times(n, f, k)))) scala> factorial(5, println) 120 scala> factorial(3, factorial(_, println)) 720 scala> val n = factorial(3, r => r) n: Int = 6
  • 18. class Regex case class Literal(s: String) extends Regex case class Concat(r1: Regex, r2: Regex) extends Regex case class Choice(r1: Regex, r2: Regex) extends Regex case class Star(r: Regex) extends Regex Concat(Star(Literal("ab")), Literal("abc")) // (ab*)abc matches abababc Choice(Star(Literal("ab")), Concat(Literal("a"), Star(Literal("ba")))) // (ab)*|a(ba)* matches abababa
  • 19. def accept (regex: Regex, chars: Seq[Char], k: Seq[Char] => Boolean): Boolean = regex match { case Literal(expect) => if(chars.take(expect.length).sameElements(expect)) k(chars.drop(expect.length)) else false case Concat(regex1, regex2) => accept(regex1, chars, remaining => accept(regex2, remaining, k)) case Choice(regex1, regex2) => accept(regex1, chars, k) || accept(regex2, chars, k) case Star(repeatable) => k(chars) || accept(repeatable, chars, remaining => accept(regex, remaining, k)) }
  • 20. def accept (regex: Regex, chars: Seq[Char], k: Seq[Char] => Boolean): Boolean = ... def complete (remaining: Seq[Char]): Boolean = remaining.length == 0 accept(regex1, "abababc", complete) // true accept(regex2, "abababa", complete) // true accept(regex1, "abababcd", complete) // false
  • 22. Delimited Continuations shift & reset
  • 23. def doSomething0 = reset { println("Ready?") val result = 1 + special * 3 println(result) } Punch a hole in your code. What type of value is expected in the hole? What happens after the hole? What is result type of the reset block?
  • 24. def doSomething0 = reset { println("Ready?") val result = 1 + special * 3 println(result) } Think of the rest of the computation as a function with the hole as its parameter. Call it the continuation.
  • 25. def doSomething1 = reset { println("Ready?") val result = 1 + special * 3 println(result) } def special = shift { k: (Int => Unit) => println(99) "Gotcha!" shift captures the continuation and } then determines its own future.
  • 26. def doSomething1 = reset { println("Ready?") val result = 1 + special * 3 println(result) } def special = shift { k: (Int => Unit) => println(99) "Gotcha!" shift doSomething1 scala> captures the continuation and } Ready?determines its own future. then 99 res0: java.lang.String = Gotcha!
  • 27. def doSomething2 = reset { println("Ready?") val result = 1 + wacky * 3 println(result) } def wacky = shift { k: (Int => Unit) => k(2) println("Yo!") k(3) }
  • 28. def doSomething2 = reset { println("Ready?") val result = 1 + wacky * 3 println(result) } def wacky = shift { k: (Int => Unit) => k(2) println("Yo!") scala> doSomething2 k(3) Ready? } 7 Yo! 10
  • 29. Continuation low-level control-flow primitive that can implement: exceptions concurrency (actors) suspensions (lazy) …
  • 30. def multi = reset { println("This function returns tentatively") println("but you can always ask for more.") produce(42) println("Didn't like that? Back again.") produce(99) println("Still not OK? I'm out of ideas!") None }
  • 31. def multi = reset { println("This function returns tentatively") println("but you can always ask for more.") produce(42) println("Didn't like that? Back again.") scala> multi produce(99) function returns tentatively This println("Still can alwaysI'm out more. but you not OK? ask for of ideas!") None res0: Option[ReturnThunk[Int]] = Some(...) } scala> println(res0.get.value) 42 scala> res0.get.proceed Didn’t like that? Back again. res1: Option[ReturnThunk[Int]] = Some(...) scala> println(res1.get.value) 99 scala> res1.get.proceed Still not OK? I’m out of ideas! res2: Option[ReturnThunk[Int]] = None
  • 32. def multi = reset { println("This function returns tentatively") println("but you can always ask for more.") produce(42) println("Didn't like that? Back again.") produce(99) println("Still not OK? I'm out of ideas!") None }
  • 33. case class ReturnThunk[A] (value: A, proceed: Unit => Option[ReturnThunk[A]]) def produce [A] (value: A): Unit @cps[Option[ReturnThunk[A]]] = shift { k: (Unit => Option[ReturnThunk[A]]) => Some(ReturnThunk(value, k)) } def multi = reset { println("This function returns tentatively") println("but you can always ask for more.") produce(42) println("Didn't like that? Back again.") produce(99) println("Still not OK? I'm out of ideas!") None }
  • 34. def interact = reset { val first = ask("Please give me a number") val second = ask("Enter another number") printf("The sum of your numbers is: %dn", first + second) }
  • 35. def interact = reset { val first = ask("Please give me a number") val second = ask("Enter another number") printf("The sum of your numbers is: %dn", first + second) } scala> interact Please give me a number respond with: submit(0x28d092b7, ...) scala> submit(0x28d092b7, 14) Enter another number respond with: submit(0x1ddb017b, ...) scala> submit(0x1ddb017b, 28) The sum of your numbers is: 42
  • 36. type UUID = Int def uuidGen: UUID = Random.nextInt type Data = Int val sessions = new HashMap[UUID, Data=>Unit] def ask(prompt: String): Data @cps[Unit] = shift { k: (Data => Unit) => { val id = uuidGen printf("%snrespond with: submit(0x%x, ...)n", prompt, id) sessions += id -> k } } def submit(id: UUID, data: Data) = sessions(id)(data) def interact = reset { val first = ask("Please give me a number") val second = ask("Enter another number") printf("The sum of your numbers is: %dn", first + second) }
  • 38. def harmful = reset { var i = 0 println("Hello world!") label("loop") println(i) i = i + 1 if(i < 20) goto("loop") println("Done.") }
  • 39. def harmful = reset { var i = 0 println("Hello world!") Hello world! label("loop") 0 println(i) 1 i = i + 1 2 . if(i < 20) goto("loop") . println("Done.") . } 18 19 Done.
  • 40. def harmful = reset { var i = 0 println("Hello world!") label("loop") println(i) i = i + 1 if(i < 20) goto("loop") println("Done.") }
  • 41. val labelMap = new HashMap[String, Unit=>Unit] def label(name:String) = shift { k:(Unit=>Unit) => labelMap += name -> k k() } def goto(name:String) = shift { k:(Unit=>Unit) => labelMap(name)() } def harmful = reset { var i = 0 println("Hello world!") label("loop") println(i) i = i + 1 if(i < 20) goto("loop") println("Done.") }
  • 42. Monads the leading design pattern for functional programming
  • 43. A type constructor M is a monad if it supports these operations: def unit[A] (x: A): M[A] def flatMap[A,B] (m: M[A]) (f: A => M[B]): M[B] def map[A,B] (m: M[A]) (f: A => B): M[B] = flatMap(m){ x => unit(f(x)) } def andThen[A,B] (ma: M[A]) (mb: M[B]): M[B] = flatMap(ma){ x => mb }
  • 44. Option is a monad. def unit[A] (x: A): Option[A] = Some(x) def flatMap[A,B](m:Option[A])(f:A =>Option[B]): Option[B] = m match { case None => None case Some(x) => f(x) }
  • 45. List is a monad. def unit[A] (x: A): List[A] = List(x) def flatMap[A,B](m:List[A])(f:A =>List[B]): List[B] = m match { case Nil => Nil case x::xs => f(x) ::: flatMap(xs)(f) }
  • 46. For comprehension: convenient syntax for monadic structures. for(i <- 1 to 4; j <- 1 to i; k <- 1 to j) yield { i*j*k } Compiler translates it to: (1 to 4).flatMap { i => (1 to i).flatMap { j => (1 to j).map { k => i*j*k }}}
  • 47. Example: a series of operations, where each may fail. lookupVenue: String => Option[Venue] getLoggedInUser: SessionID => Option[User] reserveTable: (Venue, User) => Option[ConfNo]
  • 48. Example: a series of operations, where each may fail. lookupVenue: String => Option[Venue] getLoggedInUser: SessionID => Option[User] reserveTable: (Venue, User) => Option[ConfNo] val user = getLoggedInUser(session) val confirm = if(!user.isDefined) { None } else lookupVenue(name) match { case None => None case Some(venue) => { val confno = reserveTable(venue, user.get) if(confno.isDefined) mailTo(confno.get, user.get) confno } }
  • 49. Example: a series of operations, where each may fail. lookupVenue: String => Option[Venue] getLoggedInUser: SessionID => Option[User] reserveTable: (Venue, User) => Option[ConfNo] val user = getLoggedInUser(session) val confirm = if(!user.isDefined) { None } else lookupVenue(name) match { case None => None case Some(venue) => { val confno = reserveTable(venue, user.get) if(confno.isDefined) mailTo(confno.get, user.get) confno } }
  • 50. Example: a series of operations, where each may fail. lookupVenue: String => Option[Venue] getLoggedInUser: SessionID => Option[User] reserveTable: (Venue, User) => Option[ConfNo] val confirm = for(venue <- lookupVenue(name); user <- getLoggedInUser(session); confno <- reserveTable(venue, user)) yield { mailTo(confno, user) confno }
  • 51. Example from Lift form validation: def addUser(): Box[UserInfo] = for { firstname <- S.param("firstname") ?~ "firstname parameter missing" ~> 400 lastname <- S.param("lastname") ?~ "lastname parameter missing" email <- S.param("email") ?~ "email parameter missing" } yield { val u = User.create.firstName(firstname). lastName(lastname).email(email) S.param("password") foreach u.password.set u.saveMe }
  • 52. Example: use monad to pass around state behind the scenes class Tree[A] case class Leaf[A](elem: A) extends Tree[A] case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A] inject(‘Q’, ) => f a Q c d b f g e c h g d e a h
  • 53. def inject[A] (root: Tree[A], cur: A): (Tree[A], A) = root match { case Leaf(old) => (Leaf(cur), old) case Branch(left, right) => val (t1, last1) = inject(left, cur) val (t2, last2) = inject(right, last1) (Branch(t1,t2), last2) }
  • 54. def inject[A] (root: Tree[A], cur: A): (Tree[A], A) = root match { case Leaf(old) => (Leaf(cur), old) case Branch(left, right) => val (t1, last1) = inject(left, cur) val (t2, last2) = inject(right, last1) (Branch(t1,t2), last2) } def injectST[A] (root: Tree[A]): ST[A, Tree[A]] = root match { case Leaf(old) => for(cur <- init[A]; u <- update[A](_ => old)) yield Leaf(cur) case Branch(left, right) => for(t1 <- injectST(left); t2 <- injectST(right)) yield Branch(t1,t2) }
  • 55. case class ST[S,A](exec: S => (S,A)) { def flatMap[B] (f: A => ST[S,B]): ST[S,B] = ST { s0 => val (s1, a) = exec(s0) f(a).exec(s1) } def map[B] (f: A => B) (implicit unit: B => ST[S,B]) : ST[S,B] = flatMap { x => unit(f(x)) } } implicit def unitST[S,A] (x: A): ST[S,A] = ST { s0 => (s0, x) } def init[S]: ST[S,S] = ST { s0 => (s0, s0) } def update[S] (g: S => S): ST[S,Unit] = ST { s0 => (g(s0), ()) }
  • 56. case class ST[S,A](exec: S => (S,A)) { def flatMap[B] (f: scala> ST[S,B]): ST[S,B] = A => drawTree(t1,"") ST { s0 => ______f | _____d val (s1, a) = exec(s0) | _____e f(a).exec(s1) | __c } _____a ________h | __g def map[B] (f: A => B) __b (implicit unit: B => ST[S,B]) : ST[S,B] = flatMap { x => unit(f(x)) m }= injectST(t1) scala> val m: ST[Char,Tree[Char]] = ST(<function1>) } scala> val (_,t2) = m.exec('Q') t2: Tree[Char] = ... implicit def unitST[S,A] (x: A): ST[S,A] = ST { s0 => (s0, x) scala> drawTree(t2,"") } ______Q def init[S]: ST[S,S] | _____f = | _____d ST { s0 => (s0, s0)| } __e _____c ________a def update[S] (g: S => S): ST[S,Unit] | __h = ST { s0 => (g(s0), ()) } __g
  • 57.
  • 58. Monadologie github.com/league/scala-type-anxiety @chrisleague league@contrapunctus.net