Why does Scala have both unapply and unapplySeq? What is the difference between the two? When should I prefer one over the other?
Without going into details and simplifying a bit:
For regular parameters apply constructs and unapply de-structures:
object S {
def apply(a: A):S = ... // makes a S from an A
def unapply(s: S): Option[A] = ... // retrieve the A from the S
}
val s = S(a)
s match { case S(a) => a }
For repeated parameters, apply constructs and unapplySeq de-structures:
object M {
def apply(a: A*): M = ......... // makes a M from an As.
def unapplySeq(m: M): Option[Seq[A]] = ... // retrieve the As from the M
}
val m = M(a1, a2, a3)
m match { case M(a1, a2, a3) => ... }
m match { case M(a, as # _*) => ... }
Note that in that second case, repeated parameters are treated like a Seq and the similarity between A* and _*.
So if you want to de-structure something that naturally contains various single values, use unapply. If you want to de-structure something that contains a Seq, use unapplySeq.
Fixed-arity vs. variable arity. Pattern Matching in Scala (pdf) explains it well, with mirroring examples. I also have mirroring examples in this answer.
Briefly:
object Sorted {
def unapply(xs: Seq[Int]) =
if (xs == xs.sortWith(_ < _)) Some(xs) else None
}
object SortedSeq {
def unapplySeq(xs: Seq[Int]) =
if (xs == xs.sortWith(_ < _)) Some(xs) else None
}
scala> List(1,2,3,4) match { case Sorted(xs) => xs }
res0: Seq[Int] = List(1, 2, 3, 4)
scala> List(1,2,3,4) match { case SortedSeq(a, b, c, d) => List(a, b, c, d) }
res1: List[Int] = List(1, 2, 3, 4)
scala> List(1) match { case SortedSeq(a) => a }
res2: Int = 1
So, which do you think is exhibited in the following example?
scala> List(1) match { case List(x) => x }
res3: Int = 1
Some examples:
scala> val fruit = List("apples", "oranges", "pears")
fruit: List[String] = List(apples, oranges, pears)
scala> val List(a, b, c) = fruit
a: String = apples
b: String = oranges
c: String = pears
scala> val List(a, b, _*) = fruit
a: String = apples
b: String = oranges
scala> val List(a, _*) = fruit
a: String = apples
scala> val List(a,rest # _*) = fruit
a: String = apples
rest: Seq[String] = List(oranges, pears)
scala> val a::b::c::Nil = fruit
a: String = apples
b: String = oranges
c: String = pears
scala> val a::b::rest = fruit
a: String = apples
b: String = oranges
rest: List[String] = List(pears)
scala> val a::rest = fruit
a: String = apples
rest: List[String] = List(oranges, pears)
Related
I have two partial functions returning unit (f1, f2). For instance, something like that:
val f1 = {
case s: arg => //do some
//etc... lots of cases
}
val f2 = {
case s: anotherArg => //do some
//lots of cases
}
Is there a concise way to compose this to partial functions the way as that if
f(x) = {f1(x); f2(x)} iff f1.isDefinedAt(x) && f2.isDefinedAt(x)
f(x) = f1(x); iff f1.isDefinedAt(x) && !f2.isDefinedAt(x)
f(x) = f2(x); iff !f1.isDefinedAt(x) && f2.isDefinedAt(x)
orElse
f1 orElse f2
Scala REPL
scala> val f: PartialFunction[Int, Int] = { case 1 => 1 }
f: PartialFunction[Int,Int] = <function1>
scala> val g: PartialFunction[Int, Int] = { case 2 => 2 }
g: PartialFunction[Int,Int] = <function1>
scala> val h = f orElse g
h: PartialFunction[Int,Int] = <function1>
scala> h(1)
res3: Int = 1
scala> h(2)
res4: Int = 2
scala> h.isDefinedAt(1)
res6: Boolean = true
scala> h.isDefinedAt(2)
res7: Boolean = true
Both both functions to execute on common cases
Using List of partial functions and foldLeft
Scala REPL
scala> val f: PartialFunction[Int, Int] = { case 1 => 1 case 3 => 3}
f: PartialFunction[Int,Int] = <function1>
scala> val g: PartialFunction[Int, Int] = { case 2 => 2 case 3 => 3}
g: PartialFunction[Int,Int] = <function1>
scala> val h = f orElse g
h: PartialFunction[Int,Int] = <function1>
scala> h(3)
res10: Int = 3
scala> h(3)
res11: Int = 3
scala> val h = List(f, g)
h: List[PartialFunction[Int,Int]] = List(<function1>, <function1>)
scala> def i(arg: Int) = h.foldLeft(0){(result, f) => if (f.isDefinedAt(arg)) result + f(arg) else result }
i: (arg: Int)Int
scala> i(3)
res12: Int = 6
Although pamu's answer is good, I don't like the fact that it is bound to specific Int type. Unfortunately you didn't specify result type well enough, so I see 3 alternatives:
You want to get list of all results of all defined functions and you don't care about which function produced which result. In this case something like this would work:
def callAll[A, B](funcs: List[PartialFunction[A, B]], a: A): List[B] = funcs.foldRight(List.empty[B])((f, acc) => if (f.isDefinedAt(a)) f.apply(a) :: acc else acc)
if order of elements is not important you may use
def callAll[A, B](funcs: List[PartialFunction[A, B]], a: A): List[B] = funcs.foldLeft(List.empty[B])((f, acc) => if (f.isDefinedAt(a)) f.apply(a) :: acc else acc)
which probably will be a bit faster
You want to get Option with Some in case corresponding function is defined at the point or None otherwise. In such case something like this would work:
def callAllOption[A, B](funcs: List[PartialFunction[A, B]], a: A): List[Option[B]] = funcs.map(f => f.lift.apply(a))
If you don't want to create List explicitly, you can use varargs such as:
def callAllOptionVarArg[A, B](a: A, funcs: PartialFunction[A, B]*): List[Option[B]] = funcs.map(f => f.lift.apply(a)).toList
or such curried version to specify value after functions:
def callAllOptionVarArg2[A, B](funcs: PartialFunction[A, B]*)(a: A): List[Option[B]] = funcs.map(f => f.lift.apply(a)).toList
You call functions purely for side effects and return value is not important, in which case you can safely use second (a bit faster) callAll definition
Examples:
val f: PartialFunction[Int, Int] = {
case 1 => 1
case 3 => 3
}
val g: PartialFunction[Int, Int] = {
case 2 => 2
case 3 => 4
}
val fl = List(f, g)
println(callAll(fl, 1))
println(callAll(fl, 3))
println(callAllOption(fl, 2))
println(callAllOptionVarArg(1, f, g))
println(callAllOptionVarArg2(f, g)(3))
List(1)
List(3, 4)
List(None, Some(2))
List(Some(1), None)
List(Some(3), Some(4))
I start learning Scala and I don't quite understand some behaviors of pattern-matching. Can anyone explain to me why the first case works but the second case doesn't work?
1
def getFirstElement(list: List[Int]) : Int = list match {
case h::tail => h
case _ => -1
}
Scala> getFirstElement(List(1,2,3,4))
res: Int = 1
Scala> 1 :: List(1,2)
res: List[Int] = List(1, 1, 2)
2
def getSumofFirstTwoElement(list: List[Int]): Int = list match {
case List(a: Int, b: Int)++tail => a + b
case _ => -1
}
<console>:11: error: not found: value ++
Scala> List(1,2) ++ List(3,4,5)
res: List[Int] = List(1, 2, 3, 4, 5)
The reason is that there is no unapply method on an object of type ++. The reason that :: works is because behind the scenes it is really:
final case class ::[B](override val head: B, private[scala] var tl: List[B]) extends List[B] {
override def tail : List[B] = tl
override def isEmpty: Boolean = false
}
Source
This leads to how pattern matching is implemented in Scala. It uses extractors (or here), which are basically objects that contain an unapply method, which is provided by default with case classes.
++ is a method on object of list. I think you want:
def getSumofFirstTwoElement(list: List[Int]): Int = list match {
case a::b::tail => a + b
case _ => -1
}
In case two, ++ isn't used for unapply. You want the extractor :: to decompose the list.
A good explanation here.
scala> def getSumofFirstTwoElement(list: List[Int]): Int = list match {
| case a::b::t => a + b
| case _ => -1
| }
getSumofFirstTwoElement: (list: List[Int])Int
scala> getSumofFirstTwoElement(List(1,2,3,4))
res0: Int = 3
Given a List[Any], I want to convert it to a Option[List[String]]
def convert(ls: List[Any]) : Option[List[String]] = {
if (ls.forall(_.getClass == classOf[String]))
Some(ls.map(_.asInstanceOf[String]))
else
None
}
Is there a better way ?
Like:
scala> val bag = List("a", 1, 2.0, "b")
bag: List[Any] = List(a, 1, 2.0, b)
scala> def unbagged(vs: List[Any]): Option[List[String]] = Option(vs collect { case s: String => s}) filter (_.nonEmpty)
unbagged: (vs: List[Any])Option[List[String]]
scala> unbagged(bag)
res0: Option[List[String]] = Some(List(a, b))
scala> unbagged(List(1, 3.14))
res1: Option[List[String]] = None
or, addressing the use case:
scala> def strung(vs: List[Any]): Option[List[String]] = (Option(vs) filter (_ forall { case _: String => true case _ => false })).asInstanceOf[Option[List[String]]]
strung: (vs: List[Any])Option[List[String]]
scala> strung(bag)
res3: Option[List[String]] = None
scala> strung(List("a","b","c"))
res4: Option[List[String]] = Some(List(a, b, c))
There are already quite a few answers, but I think they're all cleverer than needed. The initial proposal in the question is not that bad, except I would replace the getClass test by isInstanceOf:
def convert(ls: List[Any]): Option[List[String]] = {
if (ls.forall(_.isInstanceOf[String]))
Some(ls.map(_.asInstanceOf[String]))
else
None
}
It's functional, copies the list only once. Yes, the list is traversed twice, but typically that it still going to be faster than throwing an exception (which is usually slow -- if you really want to go that route, at least use a ControlThrowable, which does not record the stack trace when constructed).
Besides, as #som-snytt pointed out quietly in a comment, due to erasure, you don't even need to cast all the elements inside the list. You may just as well cast the list, which, after having checked that all elements are Strings, is just as safe as any other casts:
def convert(ls: List[Any]): Option[List[String]] = {
if (ls.forall(_.isInstanceOf[String]))
Some(ls.asInstanceOf[List[String]])
else
None
}
This is simply the most efficient version, because there is no list copying at all.
There is a toString method, which can make a String from any object. So if it's not a requirement that all elements of your original List should actually be String elements, you can do this:
import scala.util.Try
def convert(l: List[Any]) : Option[List[String]] = {
Try(l.map(_.toString)).toOption
}
Try will return Some(x) if it succeeds and obtains a value x, or None otherwise.
If the conversion should succeed only if all elements are Strings, then we can do the conversion inside Try (at the first failure, Try will fail and hence we'll get None)
import scala.util.Try
def convert(l: List[Any]) : Option[List[String]] = {
Try(l.map(_.asInstanceOf[String])).toOption
}
I would recommend to use pattern matching:
def convert(l: List[Any]) : Option[List[String]] = {
Try(list.collect{
case s : String => s
case x : Any => throw new Exception()
}).toOption
}
Code is a bit ugly but it works.
It doesnt use classOf but it uses pattern matching:
scala> val l1 = List("a", 1, 12.0)
l1: List[Any] = List(a, 1, 12.0)
scala> val l2 = List[Any]("a", "b", "c")
l2: List[Any] = List(a, b, c)
scala> def convert(list: List[Any]) = {
| list.foldLeft(Some(List()): Option[List[String]]) { (x, y) =>
| x match {
| case Some(l) =>
| y match {
| case elem: String => Some(l ::: List(elem))
| case _ => None
| }
| case None => None
| }
| }
| }
convert: (list: List[Any])Option[List[String]]
scala> convert(l1)
res12: Option[List[String]] = None
scala> convert(l2)
res13: Option[List[String]] = Some(List(a, b, c))
scala>
There is a straightforward solution using scalaz :
def convert(ls: List[Any]) : Option[List[String]] =
ls.map { a => if (a.isInstanceOf[String]) Some(a.asInstanceOf[String]) else None}.sequence
Im looking to extended the iterator to create a new method takeWhileInclusive, which will operate like takeWhile but include the last element.
My issue is what is best practice to extend the iterator to return a new iterator which I would like to be lazy evaluated. Coming from a C# background I normal use IEnumerable and use the yield keyword, but such an option doesn't appear to exist in Scala.
for example I could have
List(0,1,2,3,4,5,6,7).iterator.map(complex time consuming algorithm).takeWhileInclusive(_ < 6)
so in this case the takeWhileInclusive would only have resolve the predicate on the values until I get the a result greater than 6, and it will include this first result
so far I have:
object ImplicitIterator {
implicit def extendIterator(i : Iterator[Any]) = new IteratorExtension(i)
}
class IteratorExtension[T <: Any](i : Iterator[T]) {
def takeWhileInclusive(predicate:(T) => Boolean) = ?
}
You can use the span method of Iterator to do this pretty cleanly:
class IteratorExtension[A](i : Iterator[A]) {
def takeWhileInclusive(p: A => Boolean) = {
val (a, b) = i.span(p)
a ++ (if (b.hasNext) Some(b.next) else None)
}
}
object ImplicitIterator {
implicit def extendIterator[A](i : Iterator[A]) = new IteratorExtension(i)
}
import ImplicitIterator._
Now (0 until 10).toIterator.takeWhileInclusive(_ < 4).toList gives List(0, 1, 2, 3, 4), for example.
This is one case where I find the mutable solution superior:
class InclusiveIterator[A](ia: Iterator[A]) {
def takeWhileInclusive(p: A => Boolean) = {
var done = false
val p2 = (a: A) => !done && { if (!p(a)) done=true; true }
ia.takeWhile(p2)
}
}
implicit def iterator_can_include[A](ia: Iterator[A]) = new InclusiveIterator(ia)
The following requires scalaz to get fold on a tuple (A, B)
scala> implicit def Iterator_Is_TWI[A](itr: Iterator[A]) = new {
| def takeWhileIncl(p: A => Boolean)
| = itr span p fold (_ ++ _.toStream.headOption)
| }
Iterator_Is_TWI: [A](itr: Iterator[A])java.lang.Object{def takeWhileIncl(p: A => Boolean): Iterator[A]}
Here it is at work:
scala> List(1, 2, 3, 4, 5).iterator takeWhileIncl (_ < 4)
res0: Iterator[Int] = non-empty iterator
scala> res0.toList
res1: List[Int] = List(1, 2, 3, 4)
You can roll your own fold over a pair like this:
scala> implicit def Pair_Is_Foldable[A, B](pair: (A, B)) = new {
| def fold[C](f: (A, B) => C): C = f.tupled(pair)
| }
Pair_Is_Foldable: [A, B](pair: (A, B))java.lang.Object{def fold[C](f: (A, B) => C): C}
class IteratorExtension[T](i : Iterator[T]) {
def takeWhileInclusive(predicate:(T) => Boolean) = new Iterator[T] {
val it = i
var isLastRead = false
def hasNext = it.hasNext && !isLastRead
def next = {
val res = it.next
isLastRead = !predicate(res)
res
}
}
}
And there's an error in your implicit. Here it is fixed:
object ImplicitIterator {
implicit def extendIterator[T](i : Iterator[T]) = new IteratorExtension(i)
}
scala> List(0,1,2,3,4,5,6,7).toStream.filter (_ < 6).take(2)
res8: scala.collection.immutable.Stream[Int] = Stream(0, ?)
scala> res8.toList
res9: List[Int] = List(0, 1)
After your update:
scala> def timeConsumeDummy (n: Int): Int = {
| println ("Time flies like an arrow ...")
| n }
timeConsumeDummy: (n: Int)Int
scala> List(0,1,2,3,4,5,6,7).toStream.filter (x => timeConsumeDummy (x) < 6)
Time flies like an arrow ...
res14: scala.collection.immutable.Stream[Int] = Stream(0, ?)
scala> res14.take (4).toList
Time flies like an arrow ...
Time flies like an arrow ...
Time flies like an arrow ...
res15: List[Int] = List(0, 1, 2, 3)
timeConsumeDummy is called 4 times. Am I missing something?
Why does Scala have both unapply and unapplySeq? What is the difference between the two? When should I prefer one over the other?
Without going into details and simplifying a bit:
For regular parameters apply constructs and unapply de-structures:
object S {
def apply(a: A):S = ... // makes a S from an A
def unapply(s: S): Option[A] = ... // retrieve the A from the S
}
val s = S(a)
s match { case S(a) => a }
For repeated parameters, apply constructs and unapplySeq de-structures:
object M {
def apply(a: A*): M = ......... // makes a M from an As.
def unapplySeq(m: M): Option[Seq[A]] = ... // retrieve the As from the M
}
val m = M(a1, a2, a3)
m match { case M(a1, a2, a3) => ... }
m match { case M(a, as # _*) => ... }
Note that in that second case, repeated parameters are treated like a Seq and the similarity between A* and _*.
So if you want to de-structure something that naturally contains various single values, use unapply. If you want to de-structure something that contains a Seq, use unapplySeq.
Fixed-arity vs. variable arity. Pattern Matching in Scala (pdf) explains it well, with mirroring examples. I also have mirroring examples in this answer.
Briefly:
object Sorted {
def unapply(xs: Seq[Int]) =
if (xs == xs.sortWith(_ < _)) Some(xs) else None
}
object SortedSeq {
def unapplySeq(xs: Seq[Int]) =
if (xs == xs.sortWith(_ < _)) Some(xs) else None
}
scala> List(1,2,3,4) match { case Sorted(xs) => xs }
res0: Seq[Int] = List(1, 2, 3, 4)
scala> List(1,2,3,4) match { case SortedSeq(a, b, c, d) => List(a, b, c, d) }
res1: List[Int] = List(1, 2, 3, 4)
scala> List(1) match { case SortedSeq(a) => a }
res2: Int = 1
So, which do you think is exhibited in the following example?
scala> List(1) match { case List(x) => x }
res3: Int = 1
Some examples:
scala> val fruit = List("apples", "oranges", "pears")
fruit: List[String] = List(apples, oranges, pears)
scala> val List(a, b, c) = fruit
a: String = apples
b: String = oranges
c: String = pears
scala> val List(a, b, _*) = fruit
a: String = apples
b: String = oranges
scala> val List(a, _*) = fruit
a: String = apples
scala> val List(a,rest # _*) = fruit
a: String = apples
rest: Seq[String] = List(oranges, pears)
scala> val a::b::c::Nil = fruit
a: String = apples
b: String = oranges
c: String = pears
scala> val a::b::rest = fruit
a: String = apples
b: String = oranges
rest: List[String] = List(pears)
scala> val a::rest = fruit
a: String = apples
rest: List[String] = List(oranges, pears)