Can't figure out syntax in scala compose function - scala

I am working through the red book and when checking my answers for the exercises , I found that the solution for one of the exercises (6.11) was quite different (and much more elegant and cryptic than my own solution).
Here is the code:
object Candy {
def update: Input => Machine => Machine = (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 {
_ <- State.sequence(inputs map (modify[Machine] _ compose update))
s <- get
} yield (s.coins, s.candies)
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))
The bit I am unsure of is this line:
inputs map (modify[Machine] _ compose update)
I understand how compose works but this particular syntax is really throwing me for a loop. Is there a way that this can be rewritten that is not so compact that would help a noob understand?
Thanks in advance.
Also for anyone else trying to better understand how this code works, this post I found helpful.

There are a couple of syntax features in use here:
Operator Syntax
Scala allows message sends to use whitespace instead of a period as the message sending operator, i.e.
foo.bar(baz, quux)
can also be written as
foo bar(baz, quux)
Operator Syntax, part 2
When using operator syntax with a single argument list with a single argument, the parentheses can be left off, i.e.
foo bar(baz)
can also be written as
foo bar baz
Placeholder syntax
Anonymous functions in Scala can be written using the underscore _ as a placeholder for the arguments. Roughly speaking, each underscore is replaced with each argument for the closest lexically enclosing anonymous function, in order of appearance in the source text, i.e.
val adder: (Int, Int) => Int = (x, y) => x + y
can also be written as
val adder: (Int, Int) => Int = _ + _
NOT η-expansion
The underscore _ has many uses in Scala, so sometimes if you don't look careful enough, you might confuse different usages. In this case, at a cursory glance, it seems like the underscore _ could mean that modify is η-expanded into a method value, but that is not the case. The underscore _ is an anonymous function argument placeholder.
Conclusion
So, if we put the above three syntax features together, the snippet in question desugars to
inputs.map(
// ↑ Operator Syntax
(
f => modify[Machine](f)
// ↑ Placeholder Syntax ↑
).compose(update)
// ↑ Operator Syntax
)
If you ever have doubts about what the syntax of a particular piece of code means, you can print out the internal state of the Scala compiler or the Scala REPL / "interpreter" at various phases using the -Xprint:<name-of-phase> command line option to scala. For example, this is what -Xprint:parser prints for the snippet in question:
inputs.map((modify[Machine]: (() => <empty>)).compose(update))
And this is -Xprint:typer:
inputs.map[this.State[this.Machine, Unit]](
(
(f: this.Machine => this.Machine) => $anon.this.State.modify[this.Machine](f)
).compose[this.Input](Candy.this.update)
)

Happened to stumble upon this. For anyone reading this, the underscore in inputs map (modify[Machine] _ compose update) is eta expansion, ie the _ translates the method into a function allowing this to be further composed to create a function of the form Input => State[Machine, Unit].
val t: Function1[Input, State[Machine, Unit]] = modify[Machine] _ compose update
Note that in scala3, this eta expansion takes place automagically and the _ syntax is not needed.

Related

Filtering the results of zip in Scala 2

In my scenario, there are three types: A, B and C with C being a subtype of A.
class C extends A
val a: Array[A] = ...
val b: Array[B] = ...
I've been trying to zip a and b first and then filter the results based on the type of the first element, but it seems I'm missing something here.
a.zip(b).filter(_: (A, B) => _._1.isInstanceOf[C]
This does not seem to work, since Scala completely disregards my type declaration for _ on the left side to type _ on the right side as Array[(A, B)].
Since I know isInstanceOf is not the scala way of doing things, I also considered using collect like this:
a.zip(b).collect{case x: (C, B) => x}
But this does not work, since scala does expect the types (A, B) here, rendering the type matching useless.
I'm used to Python programming, so maybe my approach is off here. Would appreciate any pointer in the right direction.
_ is an anonymous parameter, you don't "declare" it, so it's either this:
a.zip(b).filter(_._1.isInstanceOf[C])
or this:
a.zip(b).filter { x: (A, B) => x._1.isInstanceOf[C] }
(note curly braces too)
Can also write it with a partial function syntax:
a.zip(b).filter { case (a,b) => a.isInstanceOf[C] }
or (better):
a.zip(b).filter {
case (_: C, _) => true
case _ => false
}
or use collect as you suggested:
a.zip(b).collect { case x#(_: C, _) => x }
Personally, I prefer the last option over others.

Understand Scala match for case classes with two members

I've been working with Scala for a while and it still troubles me a lot. I don't know why they made it so complex. I am trying to understand matching case classes when there are only two members for this case class
def main(args: Array[String]): Unit = {
case class X(a: String, i: Int)
def doSome(x: X): Unit = {
x match {
case "x" X 1 => print("ahhh") // <---- HERE !
case X(_, _) => println("")
}
}
doSome(X("x", 1))
case class Y(a: String, i: Int, j: Int)
def doAnother(y:Y): Unit = {
y match {
case "y" X 1 => print("ahhh") // how to make similar syntax when there are more than one syntax ?
case Y(_, _,_) => println("") // this is understandable
}
}
doAnother(Y("y", 1,2))
}
How can the syntax "x" X 1 match X("x",1) and if "x" X 1 can match match X("x",1) then what matches Y("y",1,2), obviously "y" Y 1 Y 2 doesn't work?
What is so special about the first argument if we can match on "y" Y (1,2)?
At least in case of List it feels more natural to me, for example consider
List(42, 11) match {
case head :: tail =>
case Nil =>
}
as opposed to
List(42, 11) match {
case ::(head, tail) =>
case Nil =>
}
where head :: tail communicates directly the shape of the List.
As a side note, infix notation can sometimes communicate intent more clearly, for example, consider syntax of generalised constraints
implicitly[List[Int] <:< Iterable[Int]] // infix type notation seems more natural
implicitly[<:<[List[Int], Iterable[Int]]]
You don't have to use a language feature just because it is there.
In this case I can see no reason not to use the standard class matching version:
x match {
case X("x", 1) => print("ahhh")
case _ => println("")
}
}
y match {
case Y("y", 1, _) => print("ahhh")
case _ => println("")
}
Ok, so the thing I was looking for is called "Infix Types". From Scala for Impatient, 2nd edition
An infix type is a type with two type parameters, written in “infix”
syntax, with the type name between the type parameters. For example,
you can write String Map Int instead of Map[String, Int] The
infix notation is common in mathematics. For example, A × B = { (a, b)
| a Œ A, b Œ B } is the set of pairs with components of types A and B.
In Scala, this type is written as (A, B). If you prefer the
mathematical notation, you can define type ×[A, B] = (A, B) Then you
can write String × Int instead of (String, Int). All infix type
operators have the same precedence. As with regular operators, they
are left-associative unless their names end in :. For example,
String × Int × Int means ((String, Int), Int). This type is similar
to, but not the same, as (String, Int, Int), which could not be
written in infix form in Scala.
To answer your query on What is so special about the first argument if we can match on "y" Y (1,2)?: this is because of how your case class gets decomposed via its unapply method.
The preferred way of matching against a case class is how you've done in the second statement of both your methods.
However, for Y, the preferred way to match would be case Y("y", 1, 2) as mentioned in Tim's comment.
For X, a few ways you can use power of pattern matching are (similarly for Y):
case X("x", 1) => ???
case X(a, 1) => ???
case X(_, 1) => ???
case X("x", _) => ???
case x#X("x", _) =>
case X(a, b) if b > 5 => ???
The following, however, is a very bad style as it compromises readability and hence maintainability of the code
case "x" X 1 => print("ahhh")
As Mario mentioned, the way you're using pattern matching is more suited for lists instead of case classes, as it makes your code consistent with the way a list is structured (head cons tail), and thus enhances readability.
You can go through following articles for a more deeper understanding on how to exploit the power of scala's pattern matching:
https://www.artima.com/pins1ed/case-classes-and-pattern-matching.html
https://docs.scala-lang.org/tour/pattern-matching.html
https://docs.scala-lang.org/overviews/scala-book/match-expressions.html

Use of underscore in function call with Try parameters

I'm trying to understand particular use of underscore in Scala. And following piece of code I cannot understand
class Test[T, S] {
def f1(f: T => S): Unit = f2(_ map f)
def f2(f: Try[T] => Try[S]): Unit = {}
}
How is the _ treated in this case? How is the T=>S becomes Try[T]=>Try[S]?
It seems you are reading it wrongly. Look at the type of f2(Try[T] => Try[S]):Unit.
Then looking into f1 we have f: T => S.
The _ in value position desugars to f2(g => g map f).
Let's see what we know so far:
f2(Try[T] => Try[S]):Unit
f: T => S
f2(g => g map f)
Give 1. and 3. we can infer that the type of g has to be Try[T]. map over Try[T] takes T => Something, in case f which is T => S, in which case Something is S.
It may seem a bit hard to read now, but once you learn to distinguish between type and value position readin this type of code becomes trivial.
Another thing to notice def f2(f: Try[T] => Try[S]): Unit = {} is quite uninteresting and may be a bit detrimental in solving your particular question.
I'd try to solve this like that: first forget the class you created. Now implement this (replace the ??? with a useful implementation):
object P1 {
def fmap[A, B](A => B): Try[A] => Try[B] = ???
}
For bonus points use the _ as the first char in your implementation.

Understanding Scala: passing functions as arguments

I'm starting to learn Scala and I've come across a snippet from the Programming in Scala textbook which I don't quite understand. Was hoping some one could help me?
This is from Listing 9.1 from Programming in Scala, 2nd Edition.
object FileMatcher {
private def filesHere = (new java.io.File(".")).listFiles
}
private def filesMatching(matcher: String => Boolean) =
for (file <- filesHere; if matcher(file.getName)) yield file
def filesEnding(query: String) =
filesMatching(_.endsWith(query)) // ???
def filesContaining(query: String) =
filesMatching(_.contains(query)) // ???
def filesRegex(query: String) =
filesMatching(_.matches(query)) // ???
I'm a little confused with the lines that have // ???. Does the use of the _ somehow create an anonymous function that is passed to filesMatching? Or does the _ have nothing to do with this, and instead the compiler sees that filesMatching requires a function and therefore doesn't execute _.endsWith(query) as an expression but instead makes the expression a function?
extended definition
Anonymous function are defined, in their more verbose and complete form, as
(a: A, b: B, ...) => function body //using a, b, ...
E.g.
(a: String, b: String) => a ++ b // concatenates 2 Strings
inferred types
if the context provides the needed information (as when a higher order function expects a specific signature for its function arguments), you can omit the parameters' types, as
(a, b, ...) => function body //using a, b, ...
E.g.
val l = List(1, 2, 3)
//you can omit the type because filter on List[Int] expects a (Int => Boolean)
l.filter(i => i < 3)
placeholder syntax
Finally you can use a shorter form still, if your parameters are used once each and in the same order that you declare them, by the function body, as
_ ++ _ // which is equivalent to (a, b) => a ++ b
Each _ is a placeholder for the function's arguments
E.g.
filesMatching's argument is a function of type String => Boolean so you can use
_.endsWith(query) // equivalent to (s: String) => s.endsWith(query)
_.contains(query) // equivalent to (s: String) => s.contains(query)
_.matches(query) // equivalent to (s: String) => s.matches(query)
The _ as used here is shorthand for a function argument. Thus filesMatching(_.endsWith(query)) is equivalent to filesMatching(f => f.endsWith(query)). As filesMatching has as argument a function of String => Boolean, the compiler can infer that f is expected to be a String here. So you are right that this expression is an anonymous function.
This kind of operation is best done by defining function types. I found an excellent demonstration here. Combined with this post, the demonstration should clarify best practices for passing functions as arguments

How to suppress "match is not exhaustive!" warning in Scala

How can I suppress the "match is not exhaustive!" warning in the following Scala code?
val l = "1" :: "2" :: Nil
l.sliding(2).foreach{case List(a,b) => }
The only solution that I found so far is to surround the pattern matching with an additional match statement:
l.sliding(2).foreach{x => (x: #unchecked) match {case List(a,b) => }}
However this makes the code unnecessarily complex and pretty unreadable. So there must be a shorter and more readable alternative. Does someone know one?
Edit
I forgot to mention that my list l has at least 2 elements in my program. That's why I can safely suppress the warning.
Here are several options:
You can match against Seq instead of List, since Seq doesn't have the exhaustiveness checking (this will fail, like your original, on one element lists):
l.sliding(2).foreach{case Seq(a, b) => ... }
You can use a for comprehension, which will silently discard anything that doesn't match (so it will do nothing on one element lists):
for (List(a, b) <- l.sliding(2)) { ... }
You can use collect, which will also silently discard anything that doesn't match (and where you'll get an iterator back, which you'll have to iterate through if you need to):
l.sliding(2).collect{case List(a,b) => }.toList
Making it complete with ; case _ => ??? is pretty short. ??? just throws an exception. You can define your own if you're using 2.9 or before (it's new in 2.10).
It really is pretty short compared to what you need for a match annotation:
(: #unchecked)
; case _ => ???
^ One more character!
It doesn't throw a MatchError, but does that really matter?
Since your sliding(2) can possibly return one last list with only one element in it, you should also test it:
l sliding(2) foreach {
case a::b::Nil => println("two elements: " + a + b)
case l => println("one last element" + l.head)
}
implicit class RichAny[A](private val a: A) extends AnyVal {
#inline
def match_ignoring_nonexhaustive[B](f: PartialFunction[A,B]): B = f(a)
}
With this you could do the following, which actually only interprets the case match as PartialFunction:
l.sliding(2).foreach{ _ match_ignoring_nonexhaustive {case List(a,b) => }}