looking through the Scala code, the convenient array creation syntax is achieved by adding an apply method to object Array. At first, I thought this was achieved somehow through case classes because you can run the following, but this does not seem to be the case:
Array(1,2,3) match { case Array(a, b, c) => a + b + c }
I know that I also need to look at WrappedArray and all the superclasses, but I can't figure out how scala achieves this matching on Arrays (and I need to become more familiar with the scala collections class hierarchy). It certainly doesn't work with a run-of-the-mill class.
scala> class A(val x: Int)
scala> new A(4) match { case A(x) => x }
<console>:9: error: not found: value A
new A(4) match { case A(x) => x }
^
<console>:9: error: not found: value x
new A(4) match { case A(x) => x }
How do they get this to work with Array?
You can pattern match with this syntax on any class so long as you have an object with with an unapply or unapplySeq (in the case of varargs) method that returns an Option or Boolean. These are known as extractors. The lines in question from object Array are
def unapplySeq[T](x: Array[T]): Option[IndexedSeq[T]] =
if (x == null) None else Some(x.toIndexedSeq)
In your example you can get it to match using
class A(val x: Int)
object A {
def unapply(a: A) = Some(a.x)
}
so now
scala> new A(4) match { case A(x) => x }
res1: Int = 4
The Programming In Scala chapter on extractors may be useful.
For case classes, an unapply method is just one of the methods that is included for free, along with toString, equals, etc.
Note that the extractor doesn't have to have the same name as the class in question, and it doesn't have to be defined within an object object. For example, in your case you could equally write
val xyz = new { def unapply(a: A) = Some(a.x) } //extending java.lang.Object
new A(4) match { case xyz(x) => x } //Int = 4
Related
I have this hierarchy of traits and classes in Scala:
trait A
trait B[T] extends A {
def v: T
}
case class C(v:Int) extends B[Int]
case class D(v:String) extends B[String]
val l:List[A] = C(1) :: D("a") :: Nil
l.foreach(t => println(t.asInstanceOf[B[_]].v))
I cannot change the type hierarchy or the type of the list.
Is there a better way to avoid the asInstanceOf[B[_]] statement?
You might try pattern matching.
l.collect{case x :B[_] => println(x.v)}
You might try something like this:
for (x <- l.view; y <- Some(x).collect { case b: B[_] => b }) println(y.v)
It doesn't require any isInstanceOf or asInstanceOf, and never crashes, even if your list contains As that aren't B[_]s. It also doesn't create any lengthy lists as intermediate results, only small short-lived Options.
Not as concise, but also much less surprising solution:
for (x <- l) {
x match {
case b: B[_] => println(b.v)
case _ => /* do nothing */
}
}
If you could change the type of l to List[B[_]], this would be the preferable solution.
I think the most ideomatic way to do it would be to supply B with an extractor object and pattern match for B values:
object B {
def unapply[T](arg: B[T]): Some[T] = Some(arg.v)
}
l.collect{case B(x) => println(x)}
If B is declared in a source file you can't alter you might need a different name for the extractor object.
I am reading Functional Programming in Scala from Manning, authored by Paul Chiusano and Runar Bjarnason. In its 3rd chapter, there is a code to create a List and there are assignments to implement various methods of the list. Following is partial implementation of the my List
package src.Cons
sealed trait List[+A]
case object Nil extends List[Nothing]
case class Cons[+A](h:A, t:List[A]) extends List[A]
object List {
//my issue is I do not want to pass a list to sum but want to use objectName.sum notation
def sum(ints:List[Int]):Int = ints match {
case Nil => 0
case Cons(x,xs) => x+sum(xs)
}
}
Question - How can I create my list such that I can call l.sum instead of List.sum(l)?
You can "PmL", as #Gabriele Petronella has suggested, or you can move the sum() method to the Cons class, as #DeadNight wrote, but before either of those can work you have to resolve the current conflict between your List object and your List trait.
The sum() in your List object can only sum a List[Int] but your class definitions use a more generic type member and, as such, you can't use + because the compiler doesn't know how to add two A types.
If you want to restrict your List to only handling numeric types then this will work.
case class Cons[A: Numeric](h:A, t:List[A]) extends List[A] {
def sum: A = List.sum(this)
}
object List {
def sum[A](ints:List[A])(implicit ev: Numeric[A]):A = ints match {
case Nil => ev.zero
case Cons(x,xs) => ev.plus(x, sum(xs))
}
}
val x = Cons(4, Cons(2, Nil))
x.sum // res0: Int = 6
Making sum a member
The problem is, you don't know how to sum the List[A] for every type A, only a List[Int]. If there was a way to allow calls when A is an Int...
Let's take a look at the standard library for that. We're interested in Option#flatten method because:
val o1 = Option(Option(3)).flatten // compiles
val o2 = Option(4).flatten // does not compile
Notice the weird implicit ev: <:<[A, Option[B]]. This is the key here - it's a thing that compiler provides for you, but only if it is known at compile time, that your Option[A] is a subtype of Option[Option[B]] for some type B. This is the trick that we can use.
sealed trait List[+A] {
def sum(implicit ev: A <:< Int): Int = this match {
case Nil => 0
case Cons(x, xs) => x + xs.sum // <- here x is magically converted to Int, so we can use plus
}
}
case object Nil extends List[Nothing]
case class Cons[+A](h:A, t:List[A]) extends List[A]
println(Cons(4, Cons(38, Nil)).sum) // 42
ScalaFiddle
Notice that you can write <:<[A, B] as A <:< B.
NB: there's also =:=[A, B] type, for when your A is exactly Int - you can use either of those
Doing better?
Actually, std library has sum method and it's type is even weirder:
def sum(implicit ev: Numeric[A]). Doing so allows it to work on any number-like type like Double and Int, and has the operations for comparison, subtraction, multiplication, etc. So you can make it even more generic. I suggest you do it after reading a chapter about Monoids, tho :)
You can use the so-called "Pimp my Library" pattern.
Define an implicit class ListOps
implicit class ListOps[+A](list: List[A]) {
def sum = List.sum(this)
}
and now you can call list.sum. The implicit conversion will be triggered and the compiler will interpret it as ListOps(list).sum.
Move the definition of sum inside the definition of List trait
You can leave the concrete definitions to Nil & Cons
package src.Cons
sealed trait List[+A] {
def sum: Int
}
case object Nil extends List[Nothing] {
val sum: Int = 0
}
case class Cons[+A](h:A, t:List[A]) extends List[A] {
def sum: Int = h + t.sum
}
I think it's a very common mistake to compare two objects with different types, e.g.
case class User(name:Option[String])
val user = User(Some("Freewind"))
if(user.name == "Freewind") { // never be true!!!
...
}
If there any way to compare two objects while requiring they have same types?
So, strictly speaking, the "type of a variable" is always present, and can be passed around as a type parameter. For example:
val x = 5
def f[T](v: T) = v
f(x) // T is Int, the type of x
But depending on what you want to do, that won't help you. For instance, may want not to know what is the type of the variable, but to know if the type of the value is some specific type, such as this:
val x: Any = 5
def f[T](v: T) = v match {
case _: Int => "Int"
case _: String => "String"
case _ => "Unknown"
}
f(x)
Here it doesn't matter what is the type of the variable, Any. What matters, what is checked is the type of 5, the value. In fact, T is useless -- you might as well have written it def f(v: Any) instead. Also, this uses either ClassTag or a value's Class, which are explained below, and cannot check the type parameters of a type: you can check whether something is a List[_] (List of something), but not whether it is, for example, a List[Int] or List[String].
Another possibility is that you want to reify the type of the variable. That is, you want to convert the type into a value, so you can store it, pass it around, etc. This involves reflection, and you'll be using either ClassTag or a TypeTag. For example:
val x: Any = 5
import scala.reflect.ClassTag
def f[T](v: T)(implicit ev: ClassTag[T]) = ev.toString
f(x) // returns the string "Any"
A ClassTag will also let you use type parameters you received on match. This won't work:
def f[A, B](a: A, b: B) = a match {
case _: B => "A is a B"
case _ => "A is not a B"
}
But this will:
val x: Any = 5
val y = 5
import scala.reflect.ClassTag
def f[A, B: ClassTag](a: A, b: B) = a match {
case _: B => "A is a B"
case _ => "A is not a B"
}
f(x, y) // A (Any) is not a B (Int)
f(y, x) // A (Int) is a B (Any)
Here I'm using the context bounds syntax, B : ClassTag, which works just like the implicit parameter in the previous ClassTag example, but uses an anonymous variable.
One can also get a ClassTag from a value's Class, like this:
val x: Any = 5
val y = 5
import scala.reflect.ClassTag
def f(a: Any, b: Any) = {
val B = ClassTag(b.getClass)
ClassTag(a.getClass) match {
case B => "a is the same class as b"
case _ => "a is not the same class as b"
}
}
f(x, y) == f(y, x) // true, a is the same class as b
A ClassTag is limited in that it only covers the base class, but not it's type parameters. That is, the ClassTag for List[Int] and List[String] is the same, List. If you need type parameters, then you must use a TypeTag instead. A TypeTag however, cannot be obtained from a value, nor can it be used on a pattern match, due to JVM's erasure.
Examples with TypeTag can get quite complex -- not even comparing two type tags is not exactly simple, as can be seen below:
import scala.reflect.runtime.universe.TypeTag
def f[A, B](a: A, b: B)(implicit evA: TypeTag[A], evB: TypeTag[B]) = evA == evB
type X = Int
val x: X = 5
val y = 5
f(x, y) // false, X is not the same type as Int
Of course, there are ways to make that comparison return true, but it would require a few book chapters to really cover TypeTag, so I'll stop here.
Finally, maybe you don't care about the type of the variable at all. Maybe you just want to know what is the class of a value, in which case the answer is rather simple:
val x = 5
x.getClass // int -- technically, an Int cannot be a class, but Scala fakes it
It would be better, however, to be more specific about what you want to accomplish, so that the answer can be more to the point.
Scalaz has a an Equal type class (examples on Learning Scalaz). Also I noticed that sometimes scalac emits a warning when comparing unrelated types, but it seems buggy.
Actually you cannot do that with == operator since it is just like the Java Object.equals method.
Scalaz is actually resolved this issue with constructing new operator ===.
Take a look at: scalaz.syntax.EqualOps
So I'm trying to get the field and their types in a case class. At the moment I am doing it like so
typeOf[CaseClass].members.filter(!_.isMethod).foreach{
x =>
x.typeSignature match {
case _:TypeOfFieldInCaseClass => do something
case _:AnotherTypeOfFieldInCaseClass => do something
}
}
the problem is x.typeSignature is of type reflect.runtime.universe.Type which cannot match on any of the types that reside in the case class. Is there some way to do this?
Let's say you have the following case class defined:
case class CaseClass(i: Int, s: String)
with pattern matching you can achieve what you want with the following:
import scala.reflect.runtime.universe._
typeOf[CaseClass].members.filter(!_.isMethod).map(_.typeSignature).foreach {
case t if t == typeOf[Int] => print("i")
case s if s == typeOf[String] => print("s")
}
Why?
So why the first attempt does not work?
That's because in your code you are using type-patterns. Type patterns check the type of subject-to-match - which is a type signature in this case - at runtime. So by using _: Int we are asking for a type check at runtime against each type signature of non-method members of CaseClass.
But in this case what we need is a value match.
Let's take a closer look (using Scala REPL):
scala> case class CaseClass(i: Int, s: String)
defined class CaseClass
scala> typeOf[CaseClass]
res1: reflect.runtime.universe.Type = CaseClass
scala> typeOf[CaseClass].members
res2: reflect.runtime.universe.MemberScope = Scopes(method equals, method toString, ..)
scala> typeOf[CaseClass].members.filter(!_.isMethod)
res4: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(value s, value i)
scala> typeOf[CaseClass].members.filter(!_.isMethod).map(_.typeSignature)
res5: Iterable[reflect.runtime.universe.Type] = List(String, scala.Int)
So what we want to match is of type reflect.runtime.universe.Type. Note that in the last line, String and scala.Int are just string representations of these types not their actual type!
So we need to match them against different values of this type which we can easily get with typeOf[Int] and typeOf[String].
A bit more on pattern matching in Scala
You may want to make the code more concise by using the following code:
typeOf[CaseClass].members.withFilter(!_.isMethod).map(_.typeSignature).foreach {
case typeOf[Int] => print("i") // Won't Compile!
case typeOf[Int] => print("s") // Won't Compile
}
But this give you the following compile error:
not found: type typeOf
Again this is because here we need to match against a variable name beginning with an uppercase letter. So the following works:
val T = typeOf[Int]
val S = typeOf[String]
typeOf[CaseClass].members.withFilter(!_.isMethod).map(_.typeSignature).foreach {
case T => print("i")
case S => print("s")
}
For more details on pattern matching, refer to Programming in Scala. You will find a detailed explanation of pattern matching there.
In researching how to do Memoization in Scala, I've found some code I didn't grok. I've tried to look this particular "thing" up, but don't know by what to call it; i.e. the term by which to refer to it. Additionally, it's not easy searching using a symbol, ugh!
I saw the following code to do memoization in Scala here:
case class Memo[A,B](f: A => B) extends (A => B) {
private val cache = mutable.Map.empty[A, B]
def apply(x: A) = cache getOrElseUpdate (x, f(x))
}
And it's what the case class is extending that is confusing me, the extends (A => B) part. First, what is happening? Secondly, why is it even needed? And finally, what do you call this kind of inheritance; i.e. is there some specific name or term I can use to refer to it?
Next, I am seeing Memo used in this way to calculate a Fibanocci number here:
val fibonacci: Memo[Int, BigInt] = Memo {
case 0 => 0
case 1 => 1
case n => fibonacci(n-1) + fibonacci(n-2)
}
It's probably my not seeing all of the "simplifications" that are being applied. But, I am not able to figure out the end of the val line, = Memo {. So, if this was typed out more verbosely, perhaps I would understand the "leap" being made as to how the Memo is being constructed.
Any assistance on this is greatly appreciated. Thank you.
A => B is short for Function1[A, B], so your Memo extends a function from A to B, most prominently defined through method apply(x: A): B which must be defined.
Because of the "infix" notation, you need to put parentheses around the type, i.e. (A => B). You could also write
case class Memo[A, B](f: A => B) extends Function1[A, B] ...
or
case class Memo[A, B](f: Function1[A, B]) extends Function1[A, B] ...
To complete 0_'s answer, fibonacci is being instanciated through the apply method of Memo's companion object, generated automatically by the compiler since Memo is a case class.
This means that the following code is generated for you:
object Memo {
def apply[A, B](f: A => B): Memo[A, B] = new Memo(f)
}
Scala has special handling for the apply method: its name needs not be typed when calling it. The two following calls are strictly equivalent:
Memo((a: Int) => a * 2)
Memo.apply((a: Int) => a * 2)
The case block is known as pattern matching. Under the hood, it generates a partial function - that is, a function that is defined for some of its input parameters, but not necessarily all of them. I'll not go in the details of partial functions as it's beside the point (this is a memo I wrote to myself on that topic, if you're keen), but what it essentially means here is that the case block is in fact an instance of PartialFunction.
If you follow that link, you'll see that PartialFunction extends Function1 - which is the expected argument of Memo.apply.
So what that bit of code actually means, once desugared (if that's a word), is:
lazy val fibonacci: Memo[Int, BigInt] = Memo.apply(new PartialFunction[Int, BigInt] {
override def apply(v: Int): Int =
if(v == 0) 0
else if(v == 1) 1
else fibonacci(v - 1) + fibonacci(v - 2)
override isDefinedAt(v: Int) = true
})
Note that I've vastly simplified the way the pattern matching is handled, but I thought that starting a discussion about unapply and unapplySeq would be off topic and confusing.
I am the original author of doing memoization this way. You can see some sample usages in that same file. It also works really well when you want to memoize on multiple arguments too because of the way Scala unrolls tuples:
/**
* #return memoized function to calculate C(n,r)
* see http://mathworld.wolfram.com/BinomialCoefficient.html
*/
val c: Memo[(Int, Int), BigInt] = Memo {
case (_, 0) => 1
case (n, r) if r > n/2 => c(n, n-r)
case (n, r) => c(n-1, r-1) + c(n-1, r)
}
// note how I can invoke a memoized function on multiple args too
val x = c(10, 3)
This answer is a synthesis of the partial answers provided by both 0__ and Nicolas Rinaudo.
Summary:
There are many convenient (but also highly intertwined) assumptions being made by the Scala compiler.
Scala treats extends (A => B) as synonymous with extends Function1[A, B] (ScalaDoc for Function1[+T1, -R])
A concrete implementation of Function1's inherited abstract method apply(x: A): B must be provided; def apply(x: A): B = cache.getOrElseUpdate(x, f(x))
Scala assumes an implied match for the code block starting with = Memo {
Scala passes the content between {} started in item 3 as a parameter to the Memo case class constructor
Scala assumes an implied type between {} started in item 3 as PartialFunction[Int, BigInt] and the compiler uses the "match" code block as the override for the PartialFunction method's apply() and then provides an additional override for the PartialFunction's method isDefinedAt().
Details:
The first code block defining the case class Memo can be written more verbosely as such:
case class Memo[A,B](f: A => B) extends Function1[A, B] { //replaced (A => B) with what it's translated to mean by the Scala compiler
private val cache = mutable.Map.empty[A, B]
def apply(x: A): B = cache.getOrElseUpdate(x, f(x)) //concrete implementation of unimplemented method defined in parent class, Function1
}
The second code block defining the val fibanocci can be written more verbosely as such:
lazy val fibonacci: Memo[Int, BigInt] = {
Memo.apply(
new PartialFunction[Int, BigInt] {
override def apply(x: Int): BigInt = {
x match {
case 0 => 0
case 1 => 1
case n => fibonacci(n-1) + fibonacci(n-2)
}
}
override def isDefinedAt(x: Int): Boolean = true
}
)
}
Had to add lazy to the second code block's val in order to deal with a self-referential problem in the line case n => fibonacci(n-1) + fibonacci(n-2).
And finally, an example usage of fibonacci is:
val x:BigInt = fibonacci(20) //returns 6765 (almost instantly)
One more word about this extends (A => B): the extends here is not required, but necessary if the instances of Memo are to be used in higher order functions or situations alike.
Without this extends (A => B), it's totally fine if you use the Memo instance fibonacci in just method calls.
case class Memo[A,B](f: A => B) {
private val cache = scala.collection.mutable.Map.empty[A, B]
def apply(x: A):B = cache getOrElseUpdate (x, f(x))
}
val fibonacci: Memo[Int, BigInt] = Memo {
case 0 => 0
case 1 => 1
case n => fibonacci(n-1) + fibonacci(n-2)
}
For example:
Scala> fibonacci(30)
res1: BigInt = 832040
But when you want to use it in higher order functions, you'd have a type mismatch error.
Scala> Range(1, 10).map(fibonacci)
<console>:11: error: type mismatch;
found : Memo[Int,BigInt]
required: Int => ?
Range(1, 10).map(fibonacci)
^
So the extends here only helps to ID the instance fibonacci to others that it has an apply method and thus can do some jobs.