Understanding Scala for comprehension in this example code - scala

I'm new to the Scala world and have some questions regarding following code.
sealed trait Input
case object Coin extends Input
case object Turn extends Input
case class Machine(locked: Boolean, candies: Int, coins: Int)
object Candy {
def update = (i: Input) => (s: Machine) =>
(i, s) match {
case (_, Machine(_, 0, _)) => s
case (Coin, Machine(false, _, _)) => s
case (Turn, Machine(true, _, _)) => s
case (Coin, Machine(true, candy, coin)) =>
Machine(false, candy, coin + 1)
case (Turn, Machine(false, candy, coin)) =>
Machine(true, candy - 1, coin)
}
def simulateMachine(inputs: List[Input]): State[Machine, (Int, Int)] = for {
_ <- sequence(inputs map (modify[Machine] _ compose update))
s <- get
} yield (s.coins, s.candies)
}
case class State[S, +A](run: S => (A, S)) {
def map[B](f: A => B): State[S, B] =
flatMap(a => unit(f(a)))
def map2[B,C](sb: State[S, B])(f: (A, B) => C): State[S, C] =
flatMap(a => sb.map(b => f(a, b)))
def flatMap[B](f: A => State[S, B]): State[S, B] = State(s => {
val (a, s1) = run(s)
f(a).run(s1)
})
}
object State {
def modify[S](f: S => S): State[S, Unit] = for {
s <- get // Gets the current state and assigns it to `s`.
_ <- set(f(s)) // Sets the new state to `f` applied to `s`.
} yield ()
def get[S]: State[S, S] = State(s => (s, s))
def set[S](s: S): State[S, Unit] = State(_ => ((), s))
def sequence[S,A](sas: List[State[S, A]]): State[S, List[A]] =
sas.foldRight(unit[S, List[A]](List()))((f, acc) => f.map2(acc)(_ :: _))
def unit[S, A](a: A): State[S, A] =
State(s => (a, s))
}
In simulateMachine method, what is the first and second _? Feels first one is an ignored output, are those two stands for the same value?
The get is from State, how does it get the state of Machine?
yield output a Tuple, how does it matching return type State[Machine, (Int, Int)]
How to call this simulateMachine method? Looks like I need do initiate Machine state somewhere.
I don't think this document can give me the right comprehension about what is happening under the hood. How can I understand it better?

Here's a slightly more verbose version of simulateMachine that should be a bit easier to understand.
def simulateMachine(inputs: List[Input]): State[Machine, (Int, Int)] = for {
_ <- State.sequence( // this _ means "discard this 'unpacked' value"
inputs.map(
(State.modify[Machine] _).compose(update) // this _ is an eta-expansion
)
)
s <- State.get
} yield (s.coins, s.candies)
"Unpacked" value - for { value <- container } ... basically "unpacks" value from container. Semantics of unpacking is different between different containers - the most straightforward is List or Seq semantics, where value each item of the becomes value and for semantics in this case becomes just iteration. Other notable "containers" are:
Option - for semantics: value present or not + modifications of the value if present
Try - for semantics: successful computation or not + modifications of the successful
Future - for semantics: defining a chain of computations to perform when value becomes present
Practically, each monad (explaining what monad is is haaard :) Try this as a starting point) defines the way to "unpack" and "iterate". Your State is practically a monad (even though it doesn't declare this explicitly) (and btw, there's a canonical State monad you can find in 3rd party libs such as cats or scalaz)
Eta-expansion is explained in this SO answer, but in short it converts a function/method into a function object. Roughly equivalent to x => State.modify[Machine](x)
Or a completely desugared version:
def simulateMachine(inputs: List[Input]): State[Machine, (Int, Int)] = {
val simulationStep: Input => State[Machine, Unit] = (State.modify[Machine] _).compose(update) // this _ is an eta-expansion
State.sequence(inputs.map(input => simulationStep(input)))
.flatMap(_ => State.get) // `_ => xyz` creates a function that does not care about it's input
.map(machine => (machine.candies, machine.coins))
}
Note that the use of _ in _ => State.get is yet another way _ is used - now it creates a function that doesn't care about it's argument.
Now, answering questions as they are asked:
See above :)
If you look at desugared version, you'd see that the State.get is passed as a "callback" to flatMap. There are a few hoops to jump through to trace it (I'll leave it as an exercise for you :)), but essentially what it does is to replace the "result" part of the state (A) with the state itself (S)). Trick here is that it does not get the Machine at all - it just "chains" a call to "fetch" the Machine from the S part of state to A part of state.
I think desugared version should be pretty self-explanatory. Regarding the for-comprehension version - for fixes the "context" using the first call in the chain, so everything else (including yield) is executed in that "context" - specifically, it's fixed to State[_, _]. yield is essentially equivalent to calling map at the end of the chain, and in State[_, _] semantics, map replaces the A part, but preserves the S part.
Candy.simulateMachine(List(Coin, Turn, Coin, Turn)).run(Machine(false, 2, 0))
P.S. your current code still misses State.set method. I'm assuming it's just def set[S](s: => S): State[S, S] = State(_ => (s, s)) - at least adding this makes your snippet compile in my environment.

Related

What does e:B, f:(B,A)=>B) : B

I am confused about what this means.
I understand currying but I can't seem to read the code altogether.
def foldLeft [A,B](xs:List[A], e:B, f:(B,A)=>B): B
Let's dive into this method signature:
foldLeft[A,B](xs: List[A], e: B, f: (B, A) => B): B
foldLeft is a method with 3 parameters
A and B are type parameters
xs is 1st parameter of the method, of type List[A]
e is 2nd parameter, of type B
f is 3rd parameter, of type (B, A) => B
the type (B, A) => B represents a function taking two parameters of type B and A respectively, and returning a B
finally, B is the return type of the method
Just a couple of advices.
By the way, there is no currying in
def foldLeft[A,B](xs: List[A], e: B, f: (B, A) => B): B
Currying would be if you had f: B => A => B or def foldLeft[A, B](xs: List[A])(e: B)(f: (B, A) => B): B or def foldLeft[A, B]: List[A] => B => ((B, A) => B) => B etc. Now foldLeft is just a higher-order function (method), i.e. a function accepting another function (f).
You can read wiki article about foldRight/foldLeft:
https://en.wikipedia.org/wiki/Fold_(higher-order_function)
Especially look at the pictures how we deconstruct a list and starting from what end we perform our calculations:
You can think of foldRight/foldLeft as a just short way to define a recursion (instead of pattern matching a list and making recursive calls).
Let's consider an example. Let's have some recursion. For example let's have a wrapper class
case class Value[A](value: A)
And let's transform a list of Value[A] into a value wrapping a list of A i.e. List[Value[A]] into Value[List[A]]. For example we'd like to transform List(Value(1), Value(2), Value(3)) into Value(List(1, 2, 3)) (I actually needed such function recently). Surely, we could do this with .map but let's pretend that we don't know map (it shouldn't be surprising that we can do mapping because map can be expressed via foldRight/foldLeft).
We can do this recursively in two ways (at least). Either simple recursion
def valuesToValue[A](values: List[Value[A]]): Value[List[A]] = values match {
case Nil => Value(Nil)
case v :: vs => Value(v.value :: valuesToValue(vs).value)
}
or tail recursion with a helper function and accumulator
def valuesToValue[A](values: List[Value[A]]): Value[List[A]] = {
#tailrec
def loop(values: List[Value[A]], acc: Value[List[A]]): Value[List[A]] = values match {
case Nil => Value(acc.value.reverse)
case v :: vs => loop(vs, Value(v.value :: acc.value))
}
loop(values, Value(Nil))
}
Very simple. Just wrapping-unwrapping.
Both recursive implementations of valuesToValue can be (automatically) re-written with foldRight/foldLeft.
The former recursion can be re-written with foldRight. The latter recursion (tail one) can be re-written with foldLeft.
Let's re-write the 1st recursion with foldRight. The value from branch case Nil => ... becomes the 1st argument of foldRight. The value from branch case v :: vs => ... becomes the 2nd argument of foldRight if we replace the result of recursive call valuesToValue(vs) with a new variable res, so in the 2nd argument of foldRight we'll have a function of v: Value[A] and res: Value[List[A]]
def valuesToValue[A](values: List[Value[A]]): Value[List[A]] =
values.foldRight( Value(Nil: List[A]) ){
(v, res) => Value(v.value :: res.value)
}
Let's re-write the 2nd recursion (tail one) with foldLeft.
First of all, let's recall that because of currying we can understand the helper loop as a single-parameter function into Value[List[A]] => Value[List[A]]
def loop(values: List[Value[A]]): Value[List[A]] => Value[List[A]] = values match {
case Nil => acc => Value(acc.value.reverse)
case v :: vs => acc => loop(vs)(Value(v.value :: acc.value))
}
Now the value from branch case Nil => ... becomes the 1st argument of foldLeft. The value from branch case v :: vs => ... becomes the 2nd argument of foldLeft if we replace the result of recursive call loop(vs)(_) with a new variable res (a function)
def valuesToValue[A](values: List[Value[A]]): Value[List[A]] = {
def loop(values: List[Value[A]]): Value[List[A]] => Value[List[A]] =
values.foldRight[Value[List[A]] => Value[List[A]]](
acc => Value(acc.value.reverse)
)(
(v, res) => acc => res(Value(v.value :: acc.value))
)
loop(values)(Value(Nil))
}
So, roughly speaking, values from branches case Nil => ... and case v :: vs => ... become arguments of foldRight/foldLeft depending on whether we calculate with simple recursion or tail recursion with accumulator.

Calling map with flatMap(for Option data type) but the types don't match in scala

I am walking through the 'Functional Programming in Scala' exercises and in chapter 4 there is this one piece of code about the Option class that I think I am having troubles to understand.
I am asked to implement flatMap. I know that Map is meant to transform an A to a B, and then wrap it in an Option. So what even is the purpose of flatMap? If I recall correctly, flatMap implemented in lists is meant to take a function that would transform A to a List of a B. A => List[B]. In principle, I imagine that applies here as well. That Option is just a list with one element and I am to give it a function that is meant to take an A and wrap it inside of an Option.
I don't know how I would implement flatMap using Map. The apparent implementation is as simple as:
def flatMap(f: A => Option[B]): Option[B] = map(f) getOrElse None
Why does this implementation work? f does not have the type signature of A=>B, yet it calls map just fine with this signature. Obviously calling getOrElse(None) is what makes it work, because if I take that out the implementation starts to complain. But I don't understand why the scala interpreter is not complaining here. We know that f returns an Option[B]. Is That returned Option calling getOrElse, which is then unwrapping its value so it can have the right type signature? If this is the case, are there other ways to write this that would be more obvious as to why it would work?
def flatMap[B](f: A => Option[B]): Option[B] =
map((a)=> f(a).getOrElse(None)) // doesn't work
Unfortunately this book does not really provide an in depth introduction to scala so I am not sure if this is syntax(pretty sure its syntactical) or logic that I am not understanding.
import scala.{Option => _, Some => _, Either => _, _} // hide std library `Option`, `Some` and `Either`, since we are writing our own in this chapter
sealed trait Option[+A] {
def map[B](f: A => B): Option[B] = this match {
case Some(a) => Some(f(a))
case None => None
}
def getOrElse[B>:A](default: => B): B = this match {
case None => default
case Some(b) => b
}
def flatMap[B](f: A => Option[B]): Option[B] =
map(f) getOrElse(None)
def orElse[B>:A](ob: => Option[B]): Option[B] = ???
def filter(f: A => Boolean): Option[A] = ???
}
case class Some[+A](get: A) extends Option[A]
case object None extends Option[Nothing]
object Option {
def mean(xs: Seq[Double]): Option[Double] =
if (xs.isEmpty) None
else Some(xs.sum / xs.length)
def variance(xs: Seq[Double]): Option[Double] = ???
def map2[A,B,C](a: Option[A], b: Option[B])(f: (A, B) => C): Option[C] = ???
def sequence[A](a: List[Option[A]]): Option[List[A]] = ???
def traverse[A, B](a: List[A])(f: A => Option[B]): Option[List[B]] = ???
}
Your intuition as to the meaning of flatMap is perfectly correct. I believe your confusion regarding the implementation stems from the fact that B is a type parameter defined per method, and as such, it doesn't have to be have the same value when one method calls the other.
To show this, let's simply give the type parameters of these methods different names:
def map[B](f: A => B): Option[B] = this match {
case Some(a) => Some(f(a))
case None => None
}
def getOrElse[C>:A](default: => C): C = this match {
case None => default
case Some(b) => b
}
def flatMap[D](f: A => Option[D]): Option[D] = {
map(f) getOrElse None
}
Now:
flatMap has a type parameter D, which can be anything.
When flatMap calls map, it assigns Option[D] as the value of map's type parameter B (!). So as far as map is concerned, it was passed a function f into some type B, which is actually Option[D] for some type D (but map doesn't care!)
When flatMap calls getOrElse - a similar thing happens, this time getOrElse's type parameter C gets assigned the value Option[B] - and again, getOrElse just "does its thing" without caring that the output happens to be an Option itself
This way, the returned value is:
None if the original input was None (because getOrElse would return the default it was passed)
None if f returned None (because getOrElse would return the value in the Some that it got, which itself is a None)
Some(v) if both the input and the result of f were Some
Which is exactly what flatMap should do.

Getting and setting state in scala

Here is some code from the Functional Programming in Scala book:
import State._
case class State[S, +A](run: S => (A, S)) {
def map[B](f: A => B): State[S, B] =
flatMap(a => unit(f(a)))
def map2[B, C](sb: State[S, B])(f: (A, B) => C): State[S, C] =
flatMap(a => sb.map(b => f(a, b)))
def flatMap[B](f: A => State[S, B]): State[S, B] = State(s => {
val (a, s1) = run(s)
f(a).run(s1)
})
}
object State {
type Rand[A] = State[RNG, A]
def unit[S, A](a: A): State[S, A] =
State(s => (a, s))
// The idiomatic solution is expressed via foldRight
def sequenceViaFoldRight[S, A](sas: List[State[S, A]]): State[S, List[A]] =
sas.foldRight(unit[S, List[A]](List.empty[A]))((f, acc) => f.map2(acc)(_ :: _))
// This implementation uses a loop internally and is the same recursion
// pattern as a left fold. It is quite common with left folds to build
// up a list in reverse order, then reverse it at the end.
// (We could also use a collection.mutable.ListBuffer internally.)
def sequence[S, A](sas: List[State[S, A]]): State[S, List[A]] = {
def go(s: S, actions: List[State[S, A]], acc: List[A]): (List[A], S) =
actions match {
case Nil => (acc.reverse, s)
case h :: t => h.run(s) match {
case (a, s2) => go(s2, t, a :: acc)
}
}
State((s: S) => go(s, sas, List()))
}
// We can also write the loop using a left fold. This is tail recursive like the
// previous solution, but it reverses the list _before_ folding it instead of after.
// You might think that this is slower than the `foldRight` solution since it
// walks over the list twice, but it's actually faster! The `foldRight` solution
// technically has to also walk the list twice, since it has to unravel the call
// stack, not being tail recursive. And the call stack will be as tall as the list
// is long.
def sequenceViaFoldLeft[S, A](l: List[State[S, A]]): State[S, List[A]] =
l.reverse.foldLeft(unit[S, List[A]](List()))((acc, f) => f.map2(acc)(_ :: _))
def modify[S](f: S => S): State[S, Unit] = for {
s <- get // Gets the current state and assigns it to `s`.
_ <- set(f(s)) // Sets the new state to `f` applied to `s`.
} yield ()
def get[S]: State[S, S] = State(s => (s, s))
def set[S](s: S): State[S, Unit] = State(_ => ((), s))
}
I have spent hours thinking about why the get and set methods look the way they do, but I just don't understand.
Could anyone enlighten me, please?
The key is on the 3rd line:
case class State[S, +A](run: S => (A, S))
The stateful computation is expressed with the run function. This function represent a transition from one state S to another state S. A is a value we could produce when moving from one state to the other.
Now, how can we take the state S out of the state-monad? We could make a transition that doesn't go to a different state and we materialise the state as A with the function s => (s, s):
def get[S]: State[S, S] = State(s => (s, s))
How to set the state? All we need is a function that goes to a state s: ??? => (???, s):
def set[S](s: S): State[S, Unit] = State(_ => ((), s))
EDIT I would like to add an example to see get and set in action:
val statefullComputationsCombined = for {
a <- State.get[Int]
b <- State.set(10)
c <- State.get[Int]
d <- State.set(100)
e <- State.get[Int]
} yield (a, c, e)
Without looking further down this answer, what is the type of statefullComputationsCombined?
Must be a State[S, A] right? S is of type Int but what is A? Because we are yielding (a, c, e) must be a 3-tuple made by the As of the flatmap steps (<-).
We said that get "fill" A with the state S so the a, c ,d are of type S, so Int. b, d are Unit because def set[S](s: S): State[S, Unit].
val statefullComputationsCombined: State[Int, (Int, Int, Int)] = for ...
To use statefullComputationsCombined we need to run it:
statefullComputationsCombined.run(1)._1 == (1,10,100)
If we want the state at the end of the computation:
statefullComputationsCombined.run(1)._2 == 100

scala Stream.takeWhile

I am implementing takeWhile method of trait Stream via foldRight.
My foldRight is following:
trait Stream[+A] {
def foldRight[B](z: => B)(f: (A, => B) => B): B =
uncons.map(t => {
f(t._1, t._2.foldRight(z)(f))
}).getOrElse(z)
}
My takeWhile is
def takeWhile(p: A => Boolean): Stream[A] =
uncons.filter(t => p(t._1)).map(t => Stream.cons(t._1, t._2.takeWhile(p))).getOrElse(Stream.empty)
But I want it to be implemented via foldRight. Here is the code:
def takeWhileViaFoldRight(p: A => Boolean): Stream[A] =
foldRight(Stream.empty)((x, acc) => {
if (p(x)) Stream.cons(x, acc) else Stream.empty
})
But my x in Stream.cons expression is underlined red with the following error: type mismatch; found : x.type (with underlying type A) required: Nothing. I guess this is because foldRight start value is Stream.empty -- with no type A indicated hence considered to be Nothing. If this is the case -- how can I tell foldRight that its return value is A, not Nothing? If not -- what's the problem then?
The courtesy of jdevelop's comment:
foldRight(Stream.empty[A])
will do the thing.

"call-cc" patterns in Scala?

I found a good article, about call with current continuation patterns. As I understand, they use Scheme and undelimited continuations. Can the patterns from the article be implemented in Scala? Is there any article about delimited continuations patterns in Scala ?
Yes, they absolutely can. callCC looks like this in Scala:
def callCC[R, A, B](f: (A => Cont[R, B]) => Cont[R, A]): Cont[R, A] =
Cont(k => f(a => Cont(_ => k(a))) run k)
Where Cont is a data structure that captures a continuation:
case class Cont[R, A](run: (A => R) => R) {
def flatMap[B](f: A => Cont[R, B]): Cont[R, B] =
Cont(k => run(a => f(a) run k))
def map[B](f: A => B): Cont[R, B] =
Cont(k => run(a => k(f(a))))
}
Here's how you might use it to simulate checked exceptions:
def divExcpt[R](x: Int, y: Int, h: String => Cont[R, Int]): Cont[R, Int] =
callCC[R, Int, String](ok => for {
err <- callCC[R, String, Unit](notOK => for {
_ <- if (y == 0) notOK("Denominator 0") else Cont[R, Unit](_(()))
r <- ok(x / y)
} yield r)
r <- h(err)
} yield r)
You would call this function as follows:
scala> divExcpt(10, 2, error) run println
5
scala> divExcpt(10, 0, error) run println
java.lang.RuntimeException: Denominator 0
Scala has an implementation of typed delimited continuations which used to be shipped with the compiler and standard library, but has been extracted to an external module and pretty much left to rot since then. It's a great shame, and I encourage anyone who's interested in delimited continuations to show that they care about its existence by using and contributing to it.