In Scala, you can do
list.filter { item =>
item match {
case Some(foo) => foo.bar > 0
}
}
But you can also do the quicker way by omitting match:
list.filter {
case Some(foo) => foo.bar > 0
}
How is this supported in Scala? Is this new in 2.9? I have been looking for it, and I can figure out what makes this possible. Is it just part of the Scala compiler?
Edit: parts of this answer are wrong; please refer to huynhjl's answer.
If you omit the match, you signal the compiler that you are defining a partial function. A partial function is a function that is not defined for every input value. For instance, your filter function is only defined for values of type Some[A] (for your custom type A).
PartialFunctions throw a MatchError when you try to apply them where they are not defined. Therefore, you should make sure, when you pass a PartialFunction where a regular Function is defined, that your partial function will never be called with an unhanded argument. Such a mechanism is very useful e.g. for unpacking tuples in a collection:
val tupleSeq: Seq[(Int, Int)] = // ...
val sums = tupleSeq.map { case (i1, i2) => i1 + i2 }
APIs which ask for a partial function, like the collect filter-like operation on collections, usually call isDefinedAt before applying the partial function. There, it is safe (and often wanted) to have a partial function that is not defined for every input value.
So you see that although the syntax is close to that of a match, it is actually quite a different thing we're dealing with.
The language specification addresses that in section 8.5. The relevant portions:
An anonymous function can be defined by a sequence of cases
{ case p1 => b1 ... case pn => bn }
If the expected type is scala.Functionk[S1, ..., Sk, R] , the expression is taken to
be equivalent to the anonymous function:
(x1 : S1, ..., xk : Sk) => (x1, ..., xk) match {
case p1 => b1 ... case pn => bn
}
If the expected type is scala.PartialFunction[S, R], the expression is taken to
be equivalent to the following instance creation expression:
new scala.PartialFunction[S, T ] {
def apply(x: S): T = x match {
case p1 => b1 ... case pn => bn
}
def isDefinedAt(x: S): Boolean = {
case p1 => true ... case pn => true
case _ => false
}
}
So typing the expression as PartialFunction or a Function influences how the expression is compiled.
Also trait PartialFunction [-A, +B] extends (A) ⇒ B so a partial function PartialFunction[A,B] is also a Function[A,B].
-- Revised post --
Hmm, I'm not sure I see a difference, Scala 2.9.1.RC3,
val f: PartialFunction[Int, Int] = { case 2 => 3 }
f.isDefinedAt(1) // evaluates to false
f.isDefinedAt(2) // evaluates to true
f(1) // match error
val g: PartialFunction[Int, Int] = x => x match { case 2 => 3 }
g.isDefinedAt(1) // evaluates to false
g.isDefinedAt(2) // evaluates to true
g(1) // match error
It seems f and g behave exactly the same as PartialFunctions.
Here's another example demonstrating the equivalence:
Seq(1, "a").collect(x => x match { case s: String => s }) // evaluates to Seq(a)
Even more interesting:
// this compiles
val g: PartialFunction[Int, Int] = (x: Int) => {x match { case 2 => 3 }}
// this fails; found Function[Int, Int], required PartialFunction[Int, Int]
val g: PartialFunction[Int, Int] = (x: Int) => {(); x match { case 2 => 3 }}
So there's some special casing at the compiler level to convert between x => x match {...} and just {...}.
Update. After reading the language spec, this seems like a bug to me. I filed SI-4940 in the bug tracker.
Related
This question already has an answer here:
Scala lists with existential types: `map{ case t => ... }` works, `map{ t => ... }` doesn't?
(1 answer)
Closed 2 years ago.
A blog describing how to use type classes to avoid F-bounded polymorphism (see Returning the "Current" Type in Scala) mentions near its end:
The problem here is that the connection between the types of p._1 and p._2 is lost in this context, so the compiler no longer knows that they line up correctly. The way to fix this, and in general the way to prevent the loss of existentials, is to use a pattern match.
I have verified the code mentioned does not work:
pets.map(p => esquire(p._1)(p._2))
while the other pattern matching variant does:
pets.map { case (a, pa) => esquire(a)(pa) }
There is also another variant not mentioned which also works:
pets.map{case p => esquire(p._1)(p._2)}
What is the magic here? Why does using case p => instead of p => preserve the existential type information?
I have tested this with Scala 2.12 and 2.13.
Scastie link to play with the code: https://scastie.scala-lang.org/480It2tTS2yNxCi1JmHx8w
The question needs to be modified for Scala 3 (Dotty), as existential types no longer exists there (pun intended). It seems it works even without the case there, as demonstrated by another scastie: https://scastie.scala-lang.org/qDfIgkooQe6VTYOssZLYBg (you can check you still need the case p even with a helper class in Scala 2.12 / 2.13 - you will get a compile error without it).
Modified code with a helper case class:
case class PetStored[A](a: A)(implicit val pet: Pet[A])
val pets = List(PetStored(bob), PetStored(thor))
println(pets.map{case p => esquire(p.a)(p.pet)})
Based on https://stackoverflow.com/a/49712407/5205022, consider the snippet
pets.map { p =>
val x = p._1
val y = p._2
esquire(x)(y)
}
after typechecking -Xprint:typer becomes
Hello.this.pets.map[Any](((p: (A, example.Hello.Pet[A]) forSome { type A }) => {
val x: Any = p._1;
val y: example.Hello.Pet[_] = p._2;
Hello.this.esquire[Any](x)(<y: error>)
}))
whilst the snippet with pattern matching
pets.map { case (a, pa) =>
val x = a
val y = pa
esquire(x)(y)
}
after typechecking becomes
Hello.this.pets.map[Any](((x0$1: (A, example.Hello.Pet[A]) forSome { type A }) => x0$1 match {
case (_1: A, _2: example.Hello.Pet[A]): (A, example.Hello.Pet[A])((a # _), (pa # _)) => {
val x: A = a;
val y: example.Hello.Pet[A] = pa;
Hello.this.esquire[A](x)(y)
}
}));
We note that in the latter pattern matching case, the existential type parameter A is re-introduced
val x: A = a;
val y: example.Hello.Pet[A] = pa;
and so relationship between x and y is re-established, whilst in the case without pattern matching the relationship is lost
val x: Any = p._1;
val y: example.Hello.Pet[_] = p._2;
I came across a code similar to this, and it was surprised that it even compiles:
scala> val halfSize: PartialFunction[String, Int] = _.length match {
case even if even % 2 == 0 => even / 2
}
halfSize: PartialFunction[String,Int] = <function1>
scala> List("x", "xx").collect(halfSize)
res1: List[Int] = List(1)
As far as I known, the valid syntax to define a PartialFunction is a case function:
val halfSize: PartialFunction[String, Int] = {
case s if s.length % 2 == 0 => s.length / 2
}
The first code seems more optimized since it calls length only once. But even in the SLS I was not able to find the explanation of the syntax. Is this an undocumented feature of scalac ?
The rules are given in https://www.scala-lang.org/files/archive/spec/2.12/06-expressions.html#anonymous-functions:
The eventual run-time value of an anonymous function is determined by the expected type:
...
PartialFunction[T, U], if the function literal is of the shape x => x match { … }
In this case the literal does have such a shape, as rogue-one's answer explains, so PartialFunction is allowed as the expected type.
(EDIT: actually, it doesn't, since it matches x.length instead of x. This looks like a minor bug, but one which should be fixed by changing the specification.)
A PartialFunction's value receives an additional isDefinedAt member, which is derived from the pattern match in the function literal, with each case's body being replaced by true, and an added default (if none was given) that evaluates to false.
So in this case it ends up with
def isDefinedAt(x: String) = x.length match {
case even if even % 2 == 0 => true
case _ => false
}
val halfSize: PartialFunction[String, Int] = _.length match {
case even if even % 2 == 0 => even / 2
}
The underscore (_) in the above function is just a short hand notation that refers to the single argument of the function. Thus the above snippet is just a short form of
val halfSize: PartialFunction[String, Int] = { (x: String) => x.length match {
case even if even % 2 == 0 => even / 2
}
}
Here is a function to memoize /cache intermediate result :
def memoize[I, O](f: I => O) = new scala.collection.mutable.HashMap[I, O]() {
override def apply(key: I): O = getOrElseUpdate(key, f(key))
}
This works fine for code like below,
val double: Int=>Int = memoize {
_*2
}
However, when I try to use tuple as input parameter(I) it shows compile time error,
val isGivenNumIsHead:(List[Int], Int) => Boolean = memoize {
case (Nil, _) => false
case (a:: as, n) => a == n
}
Compile time error is :
Expression of type mutable.HashMap[Nothing, Boolean] {def apply(key: Nothing): Boolean} doesn't conform to expected type (List[Int], Int) => Boolean
Is this something related to erasure.
How do i fix it ?
I am assuming you want to use the tuple as the key in the HashMap. With that in mind, here is the explanation.
The actual return type of memoize is scala.collection.mutable.HashMap[_,_] . That is being assigned to double which is of type Int => Int or Function1[Int,Int] ( a function that takes an integer and gives an interger). The compiler doesnt throw an error because mutable.HashMap extends scala.collection.mutable.MapLike which in turn extends scala.collection.MapLike which in turn extends scala.PartialFunction[A, B] which in turn extends scala.Function1[A, B]. Hence there is no compilation error.
On the other hand, the syntax for functions taking one parameter and returning one value is val functionName : A => B = a => {return b} or can be written as val function : (A) => B = a => {return b} or val function: (A => B) = a => {return b}. You have used the second method. In that case, the value of A should be of single type. You have used List[Int],Int which is not a single type. Note that I intentionally removed the brackets. So in order to make that as a single type and to pass it as a tuple, you have to use one more set of brackets. The correct syntax would be
val isGivenNumIsHead:((List[Int], Int)) => Boolean = memoize {
case (Nil, _) => false
case (a:: as, n) => a == n
}
Note the usage of additional brackets to make it a tuple.
Suppose I have a list of functions as so:
val funcList = List(func1: A => T, func2: B => T, func2: C => T)
(where func1, et al. are defined elsewhere)
I want to write a method that will take a value and match it to the right function based on exact type (match a: A with func1: A => T) or throw an exception if there is no matching function.
Is there a simple way to do this?
This is similar to what a PartialFunction does, but I am not able to change the list of functions in funcList to PartialFunctions. I am thinking I have to do some kind of implicit conversion of the functions to a special class that knows the types it can handle and is able to pattern match against it (basically promoting those functions to a specialized PartialFunction). However, I can't figure out how to identify the "domain" of each function.
Thank you.
You cannot identify the domain of each function, because they are erased at runtime. Look up erasure if you want more information, but the short of it is that the information you want does not exist.
There are ways around type erasure, and you'll find plenty discussions on Stack Overflow itself. Some of them come down to storing the type information somewhere as a value, so that you can match on that.
Another possible solution is to simply forsake the use of parameterized types (generics in Java parlance) for your own customized types. That is, doing something like:
abstract class F1 extends (A => T)
object F1 {
def apply(f: A => T): F1 = new F1 {
def apply(n: A): T = f(n)
}
}
And so on. Since F1 doesn't have type parameters, you can match on it, and you can create functions of this type easily. Say both A and T are Int, then you could do this, for example:
F1(_ * 2)
The usual answer to work around type erasure is to use the help of manifests. In your case, you can do the following:
abstract class TypedFunc[-A:Manifest,+R:Manifest] extends (A => R) {
val retType: Manifest[_] = manifest[R]
val argType: Manifest[_] = manifest[A]
}
object TypedFunc {
implicit def apply[A:Manifest, R:Manifest]( f: A => R ): TypedFunc[A, R] = {
f match {
case tf: TypedFunc[A, R] => tf
case _ => new TypedFunc[A, R] { final def apply( arg: A ): R = f( arg ) }
}
}
}
def applyFunc[A, R, T >: A : Manifest]( funcs: Traversable[TypedFunc[A,R]] )( arg: T ): R = {
funcs.find{ f => f.argType <:< manifest[T] } match {
case Some( f ) => f( arg.asInstanceOf[A] )
case _ => sys.error("Could not find function with argument matching type " + manifest[T])
}
}
val func1 = { s: String => s.length }
val func2 = { l: Long => l.toInt }
val func3 = { s: Symbol => s.name.length }
val funcList = List(func1: TypedFunc[String,Int], func2: TypedFunc[Long, Int], func3: TypedFunc[Symbol, Int])
Testing in the REPL:
scala> applyFunc( funcList )( 'hello )
res22: Int = 5
scala> applyFunc( funcList )( "azerty" )
res23: Int = 6
scala> applyFunc( funcList )( 123L )
res24: Int = 123
scala> applyFunc( funcList )( 123 )
java.lang.RuntimeException: Could not find function with argument matching type Int
at scala.sys.package$.error(package.scala:27)
at .applyFunc(<console>:27)
at .<init>(<console>:14)
...
I think you're misunderstanding how a List is typed. List takes a single type parameter, which is the type of all the elements of the list. When you write
val funcList = List(func1: A => T, func2: B => T, func2: C => T)
the compiler will infer a type like funcList : List[A with B with C => T].
This means that each function in funcList takes a parameter that is a member of all of A, B, and C.
Apart from this, you can't (directly) match on function types due to type erasure.
What you could instead do is match on a itself, and call the appropriate function for the type:
a match {
case x : A => func1(x)
case x : B => func2(x)
case x : C => func3(x)
case _ => throw new Exception
}
(Of course, A, B, and C must remain distinct after type-erasure.)
If you need it to be dynamic, you're basically using reflection. Unfortunately Scala's reflection facilities are in flux, with version 2.10 released a few weeks ago, so there's less documentation for the current way of doing it; see How do the new Scala TypeTags improve the (deprecated) Manifests?.
in scala play framework I seen this code:
abstract class AnalyserInfo
case class ColumnC(typeName:String,fieldName:String) extends AnalyserInfo
case class TableC(typeName:String) extends AnalyserInfo
val asIs :PartialFunction[AnalyserInfo,String] = {
case ColumnC(_,f) => f;
case TableC(typeName) => typeName
}
What is the difference with:
val asIs: (AnaliserInfo)=>String = (info) => info match {
case ColumnC(_,f) => f;
case TableC(typeName) => typeName
}
There is a preferred style? and why in the first case the match keyword can be omitted?
Thank you for the support.
Double => Double is just a shorthand for Function[Double, Double]. PartialFunction inherits from Function but adds a few methods. Most importantly, it adds the method isDefinedAt which allows you to query if the function is defined for some parameter.
The cases without a match are a special syntax to define partial functions, which generates an isDefinedAt that returns true for all matching cases.
Say we have a function that returns 1/x, but only for positive values of x, we could it define as:
scala> val f: (Double => Double) = { case x if x > 0 => 1/x }
f: (Double) => Double = <function1>
or as:
scala> val g: PartialFunction[Double, Double] = { case x if x > 0 => 1/x }
g: PartialFunction[Double,Double] = <function1>
The second version has the benefit that we could check if the function is applicable to some parameter:
scala> g.isDefinedAt(-3)
res0: Boolean = false
This feature is for example used in Scala to implement the actor library where an Actor might only consume certain types of messages.