And why they are so useful

Slides:



Advertisements
Similar presentations
Intro to Scala Lists. Scala Lists are always immutable. This means that a list in Scala, once created, will remain the same.
Advertisements

More about functions Plus a few random things. 2 Tail recursion A function is said to be tail recursive if the recursive call is the very last thing it.
CS162 Week 2 Kyle Dewey. Overview Continuation of Scala Assignment 1 wrap-up Assignment 2a.
Patterns in ML functions. Formal vs. actual parameters Here's a function definition (in C): –int add (int x, int y) { return x + y; } –x and y are the.
Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.
Haskell Chapter 8. Input and Output  What are I/O actions?  How do I/O actions enable us to do I/O?  When are I/O actions actually performed?
Functional Programming in Scheme and Lisp. Overview In a functional programming language, functions are first class objects. You can create them, put.
Patterns in OCaml functions. Formal vs. actual parameters Here's a function definition (in C): –int add (int x, int y) { return x + y; } –x and y are.
Functional Programming and Lisp. Overview In a functional programming language, functions are first class objects. In a functional programming language,
Functional Programming With examples in F#. Pure Functional Programming Functional programming involves evaluating expressions rather than executing commands.
Functions and Methods. Definitions and types A function is a piece of code that takes arguments and returns a result A pure function is a function whose.
0 Odds and Ends in Haskell: Folding, I/O, and Functors Adapted from material by Miran Lipovaca.
CMSC 330: Organization of Programming Languages Functional Programming with OCaml.
Cases and Classes and Case Classes And Other Miscellany 16-Dec-15.
Monads. foo1 Method to print a string, then return its length: scala> def foo1(bar: String) = { | println(bar) | bar.size | } foo1: (bar: String)Int scala>
23-Feb-16 Lists. Arrays and Lists Arrays are a fixed length and occupy sequential locations in memory This makes random access (for example, getting the.
Quiz 3 Topics Functions – using and writing. Lists: –operators used with lists. –keywords used with lists. –BIF’s used with lists. –list methods. Loops.
24-Jun-16 Haskell Dealing with impurity. Purity Haskell is a “pure” functional programming language Functions have no side effects Input/output is a side.
Haskell Chapter 8.
Prof: Dr. Shu-Ching Chen TA: Samira Pouyanfar Spring 2017
Theory of Computation Lecture 4: Programs and Computable Functions II
Class Structure 15-Jun-18.
CS-104 Final Exam Review Victor Norman.
Classes and Objects and Traits
Expanded Recursive Diagrams OCAML rapid tour, day 2
Getting Functional.
Exceptions and other things
Error Handling Summary of the next few pages: Error Handling Cursors.
Lists 20-Sep-18.
PROGRAMMING IN HASKELL
CSE341: Programming Languages Lecture 15 Macros
Functions Inputs Output
Subroutines Idea: useful code can be saved and re-used, with different data values Example: Our function to find the largest element of an array might.
Important Concepts from Clojure
Important Concepts from Clojure
Functions As Objects.
Haskell Dealing with impurity 30-Nov-18.
CISC101 Reminders Assn 3 due tomorrow, 7pm.
Plus a few random things
Pattern Matching.
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
Getting Started with Scala
CSE341: Programming Languages Lecture 15 Macros
Cases and Classes and Case Classes
Getting Functional.
CSE 341 PL Section 2 Justin Harjanto.
PROGRAMMING IN HASKELL
Type & Typeclass Syntax in function
Barb Ericson Georgia Institute of Technology Oct 2005
Fundamentals of Functional Programming
Plus a few random things
The Scala API.
Important Concepts from Clojure
Haskell Dealing with impurity 8-Apr-19.
CSE341: Programming Languages Lecture 15 Macros
Classes and Objects and Traits
Programming Languages
Plus a few random things
Scala Apologia 27-Apr-19.
Haskell Dealing with impurity 29-May-19.
CISC101 Reminders Assignment 3 due today.
CMPE212 – Reminders Assignment 2 due next Friday.
Plus a few random things
Haskell Dealing with impurity 28-Jun-19.
Monads.
Plus a few random things
Functions John R. Woodward.
Plus a few random things
Presentation transcript:

And why they are so useful Monads And why they are so useful

flatMap revisited The flatMap method is like Map, but removes one level of nesting from a sequence scala> List(2, 3, 4, 5) map (x => List(x, x * x, x * x * x)) res21: List[List[Int]] = List(List(2, 4, 8), List(3, 9, 27), List(4, 16, 64), List(5, 25, 125)) scala> List(2, 3, 4, 5) flatMap (x => List(x, x * x, x * x * x)) res22: List[Int] = List(2, 4, 8, 3, 9, 27, 4, 16, 64, 5, 25, 125) Used with a sequence of Option, flatMap effectively reduces Some(x) to x, and entirely deletes None scala> List(1, -1, 2, 4, -5, 9) flatMap (root(_)) res17: List[Double] = List(1.0, 1.4142135623730951, 2.0, 3.0)

map and for…yield val nums = List(1, 2, 3) List(1, 2, 3) nums map (_ * 2) List(2, 4, 6) for (n <- nums) yield (n * 2) List(2, 4, 6) nums map (n => List(n, 2 * n, 3 * n)) List(List(1, 2, 3), List(2, 4, 6), List(3, 6, 9)) nums map (n => List(n, 2 * n, 3 * n)) flatten List(1, 2, 3, 2, 4, 6, 3, 6, 9) nums flatMap (n => List(n, 2 * n, 3 * n)) List(1, 2, 3, 2, 4, 6, 3, 6, 9)

More map and for…yield for (x <- List(1, 2, 3); y <- List(10, 100)) yield x * y List(10, 100, 20, 200, 30, 300) List(1, 2, 3) flatMap { x => List(10, 100) map (y => x * y) } List(10, 100, 20, 200, 30, 300) for (x <- List(1, 2, 3, 4) if x != 3) yield 2 * x List(2, 4, 8) List(1, 2, 3, 4) filter (_ != 3) map (2 * _) List(2, 4, 8) for…yield is not a loop—it is syntactic sugar for a sequence of map, flatmap, and filter operations Of course, those operations may be implemented using loops for without a yield is equivalent to a foreach

Functors In Scala terms, a functor is anything that has a map operation Scala’s collections (lists, arrays, sets, maps, strings, etc.) have a map operation It is implemented differently for different collection types trait F[T] { def map(f: T => S): F[S] }

The Option type Scala has null because it interoperates with Java; it shouldn’t be used any other time Instead, use an Option type, with values Some(value) and None def max(list: List[Int]) = { if (list.length > 0) { val big = list reduce {(a, b) => if (a > b) a else b} Some(big) } else { None } max(myList) match { case Some(x) => println("The largest number is " + x) case None => println("There are no numbers here!!!") }

Try scala> import scala.util.{Try, Success, Failure} import scala.util.{Try, Success, Failure} scala> def root2(x: Double): Try[Double] = | if (x >= 0) Success(math.sqrt(x)) else | Failure(new Exception("Imaginary root")) root2: (x: Double)scala.util.Try[Double] scala> root2(10) res28: scala.util.Try[Double] = Success(3.1622776601683795) scala> root2(-10) res29: scala.util.Try[Double] = Failure(java.lang.Exception: Imaginary root)

Containers I The map operation is also useful for various types of containers Some(5) map (x => 2 * x) Some(10) val nope: Option[Int] = None None import scala.util.{Try, Success, Failure} Success(5) map (x => 2 * x) Success(10) val fail: Try[Int] = Failure(new Exception) fail map (x => 2 * x) Failure(java.lang.Exception)

Containers II import scala.concurrent._ import scala.concurrent.duration._ import scala.concurrent.ExecutionContext.Implicits.global val foo = Future{42} map (x => 2 * x) List() Await.result(foo, 1 nano) 84 Therefore, Option (Some, None), Try (Success, Failure), and Future are also functors

Monad as a trait In Scala, we could define a monad trait as follows: trait M[A] { def flatMap[B](f: A => M[B]): M[B] } def unit[A](x: A): M[A] You can think of unit as a constructor, or better yet, as a factory method There isn’t actually any unit method in Scala, but there is apply Notice that monads have a type parameter (A) If a Scala object has a constructor with a type parameter and a flatMap operation, it’s a monad! Scala is full of monads Examples: List, Set, Map, Array, String, Option, Try, Future, to name a few

Comparing map and flatMap val listA: List[A] = … final def map[B](f: (A) ⇒ B): List[B] final def flatMap[B](f: (A) ⇒ M[B]): List[B] where M = GenTraversableOnce val nums = List(1, 10, 100) x map (v => List(v - 1, v, v + 1)) res0: List[List[Int]] = List(List(0, 1, 2), List(9, 10, 11), List(99, 100, 101)) x flatMap (v => List(v - 1, v, v + 1)) res1: List[Int] = List(0, 1, 2, 9, 10, 11, 99, 100, 101)

Monad in Haskell and Scala Remember Haskell? A monad consists of three things: A type constructor M A bind operation, (>>=) :: (Monad m) => m a -> (a -> m b) -> m b A return operation, return :: (Monad m) => a -> m a Compare: A Haskell type constructor with a Scala type declaration A Haskell bind operation with Scala’s flatMap Haskell: m a -> (a -> m b) -> m b Scala: M(A).(f: A => M[B]): M[B] A Haskell return operation with a Scala constructor (or unit)

andThen does sequencing scala> def double(x: Int) = 2 * x double: (x: Int)Int scala> def triple(x: Int) = 3 * x triple: (x: Int)Int scala> ((double _) andThen (triple _))(5) res4: Int = 30 scala> def upper(s: String) = s.toUpperCase upper: (s: String)String scala> def addXs(s: String) = "x" + s + "x" addXs: (s: String)String scala> ((upper _) andThen (addXs _))("Hello") res10: String = xHELLOx

foo1 Method to print a string, then return its length: scala> def foo1(bar: String) = { | println(bar) | bar.size | } foo1: (bar: String)Int scala> foo1("Hello") Hello res0: Int = 5

foo2 Here’s the same method, but replacing each expression with an anonymous function: scala> def foo1(bar: String) = { | (() => println(bar))() | (() => bar.length)() | } foo1: (bar: String)Int scala> foo2("Hello") Hello res1: Int = 5

andThen applied to foo Consider this form: The above almost works… def foo(bar: String) = { ({ () => println(bar) } andThen { () => bar.length })() } The above almost works… andThen is not defined for 0-argument functions Basically, what this achieves is sequencing in a purely functional manner In pure functions, there is no concept of sequencing

Thing Compare: def foo(i: Int) = i + 1 val a = 1 val b = foo(a) With: case class Thing[+A](value: A) val a = Thing(1) val b = Thing(2) def foo(i: Int) = Thing(i + 1) val a = Thing(1) val b = foo(a.value) The difference is that in the second, the value is “wrapped” in a Thing container

Monads as wrappers Is Thing a monad? A monad consists of three things: A type constructor M A bind operation, (>>=) :: (Monad m) => m a -> (a -> m b) -> m b A return operation, return :: (Monad m) => a -> m a Is Thing a monad? It has a type constructor, Thing It has a return operation, Thing(i) Let’s give it a bind operation: case class Thing[+A](value: A) { def bind[B](f: A => Thing[B]) = f(value) }

The Thing monad Here’s what we had before: Here’s what we have now: scala> val a = Thing(1) a: Thing[Int] = Thing(1) scala> val b = foo(a.value) b: Thing[Int] = Thing(2) Here’s what we have now: scala> val a = Thing(1) a: Thing[Int] = Thing(1) scala> val b = a bind foo b: Thing[Int] = Thing(2) We have additional syntax, but really, nothing’s changed

The monad pattern Any time you start with something which you pull apart and use to compute a new something of that same type, you have a monad. val a = Thing(1) The first thing is that I can wrap up a value inside of a new Thing. Object-oriented developers might call this a “constructor”. Monads call it “the unit function”. Haskell calls it “return” (maybe we shouldn’t try to figure out that one). a bind { i => Thing(i + 1) } We also have this fancy bind function, which digs inside our Thing and allows a function which we supply to use that value to create a new Thing. Scala calls this function “flatMap”. Haskell calls it “>>=”. …What’s interesting here is the fact that bind is how you combine two things together in sequence. Directly quoted from www.codecommit.com/blog/

bind == flatMap Scala’s for expression is translated into map, flatMap, and withFilter operations Multiple generators lead to a flatMap for (x <- expr1; y <- expr2; seq) yield expr3 gets translated to expr1.flatMap(x => for (y <- expr2; seq) yield expr3) Repeated use of flatMap will change List[List[List[items]]] into just List[items]

Using flatMap scala> for (v <- List(1, 2, 3, -1, 4)) { | val Some(rootOfV) = root(v) | println(rootOfV) | } 1.0 1.4142135623730951 1.7320508075688772 scala.MatchError: None (of class scala.None$) scala> for (v <- List(1, 2, 3, -1, 4) flatMap (root(_))) println(v) 1.0 1.4142135623730951 1.7320508075688772 2.0

Option A value of type Option[T] can be either Some[value] or None, where value is of type T scala> def root(x: Double): Option[Double] = | if (x >= 0) Some(math.sqrt(x)) else None root: (x: Double)Option[Double] scala> root(10.0) res14: Option[Double] = Some(3.1622776601683795) scala> root(-5.0) res15: Option[Double] = None

Repeated flatMap Let’s say we want to load a user from the database and if he exists we want to see if he has a grandchild. We need to invoke these three functions: String → Option[User] // load from db User → Option[User] // get child User → Option[User] // get child’s child Here’s the code. val result = UserService.loadUser("mike") .flatMap(getChild) .flatMap(getChild) Or we can do this: val result = for { user <- UserService.loadUser("mike) usersChild <- user.child usersGrandChild <- usersChild.child } yield usersGrandChild Example from: https://medium.com/@sinisalouc/demystifying-the-monad-in-scala-cc716bb6f534#.jf1x02xm9

bind for Option sealed trait Option[+A] { def bind[B](f: A => Option[B]): Option[B] } case class Some[+A](value: A) extends Option[A] { def bind[B](f: A => Option[B]) = f(value) } case object None extends Option[Nothing] { def bind[B](f: Nothing => Option[B]) = None }

Maintaining state A purely functional language has no notion of “state” (or time, or change…) Everything relevant to a function is in its parameters Therefore, a function that “changes state” must be called recursively with different parameters Consider an adventure game State includes the location of each object and the location of the player—this is easily done with a Map The state usually includes other information (is the dragon alive?)—we can put this in a tuple along with the Map Player’s actions can be implemented with a function that takes a State and computes a new State—that is, a monad

Life, the Universe, and Everything Passing around the entire “state of the universe” in parameters seems excessive, but… Typically a very large proportion of the information is immutable, and need not be part of the state You have to depend on the quality of the implementation of persistent data structures Scala has a specific State monad I haven’t explored this, but I’ve read that it’s complicated

A “functional” println def foo(bar: String, stdout: Vector[String]) = { val stdout2 = println(bar, stdout) (bar.length, stdout2) } def println(str: String, stdout: Vector[String]) = stdout + str Now we can use andThen Functional input is trickier—we won’t go there Haskell does this for everything!

And then there’s the IO monad… Haskell’s IO monad is like our earlier “functional” println, only richer and with a better syntax Like all monads, it pulls apart some kind of thing, and creates a new thing from it The weird part is, I/O happens along the way Output doesn’t affect the result Input does affect the result The IO monad (1) achieves sequencing, and (2) isolates the I/O side effects from the rest of the program In Scala we could use a functional println to implement (part of) an IO monad—but why bother?

The End Substantial portions of this talk taken from: http://www.codecommit.com/blog/