In Scala, is there any difference at all between Nil and List()?
If not, which one is more idiomatic Scala style? Both for creating new empty lists and pattern matching on empty lists.
scala> println (Nil == List())
true
scala> println (Nil eq List())
true
scala> println (Nil equals List())
true
scala> System.identityHashCode(Nil)
374527572
scala> System.identityHashCode(List())
374527572
Nil is more idiomatic and can be preferred in most cases.
Questions?
User unknown has shown that the run time value of both Nil and List() are the same. However, their static type is not:
scala> val x = List()
x: List[Nothing] = List()
scala> val y = Nil
y: scala.collection.immutable.Nil.type = List()
scala> def cmpTypes[A, B](a: A, b: B)(implicit ev: A =:= B = null) = if (ev eq null) false else true
cmpTypes: [A, B](a: A, b: B)(implicit ev: =:=[A,B])Boolean
scala> cmpTypes(x, y)
res0: Boolean = false
scala> cmpTypes(x, x)
res1: Boolean = true
scala> cmpTypes(y, y)
res2: Boolean = true
This is of particular importance when it is used to infer a type, such as in a fold's accumulator:
scala> List(1, 2, 3).foldLeft(List[Int]())((x, y) => y :: x)
res6: List[Int] = List(3, 2, 1)
scala> List(1, 2, 3).foldLeft(Nil)((x, y) => y :: x)
<console>:10: error: type mismatch;
found : List[Int]
required: scala.collection.immutable.Nil.type
List(1, 2, 3).foldLeft(Nil)((x, y) => y :: x)
^
As user unknown's answer shows, they are the same object.
Idiomatically Nil should be preferred because it is nice and short. There's an exception though: if an explicit type is needed for whatever reason I think
List[Foo]()
is nicer than
Nil : List[Foo]
Related
If:
scala> val l = List() // List() same as List[Nothing]()
l: List[Nothing] = List()
scala> 1 :: l
res0: List[Int] = List(1)
or:
scala> 1 :: List[Nothing]()
res6: List[Int] = List(1)
Why then this does not work out:
scala> List(1,2,3). foldLeft( List() ) ((acc,x) => x :: acc)
So I have to type this explicitly List[Int]():
scala> List(1,2,3). foldLeft( List[Int]() ) ((acc,x) => x :: acc)
res3: List[Int] = List(3, 2, 1)
?
Though it does in Haskell, for example:
foldl (\acc x -> x:acc) [] [1,2,3]
Let's look at scala's foldLeft signature:
List[+A].foldLeft[B](z: B)(f: (B, A) ⇒ B): B
and haskell's signature:
foldl :: (b -> a -> b) -> b -> [a] -> b
They pretty much same, but:
1) scala has problem with type inference between [pseudo-]curried parameter lists, just compare:
scala> def aaa[A](a: A)(b: A) = {}
aaa: [A](a: A)(b: A)Unit
scala> aaa(null: Any)(5)
scala> aaa(5)(null: Any)
<console>:21: error: type mismatch;
found : Any
required: Int
aaa(5)(null: Any)
^
So scala can choose bigger type from left to right only.
More than that, this is a problem only for [pseudo-]curried functions:
scala> def aaa[T](a: T, b: T) = a
aaa: [T](a: T, b: T)T
scala> aaa(List("a"), List(6.0))
res26: List[Any] = List(a)
scala> aaa(List(6.0), List("a"))
res27: List[Any] = List(6.0)
Here scala not only picked a bigger type - it found a common supertype of both T's. So, it's trying to choose bigger type (if it's in the left part) by default, but looking for a common supertype inside one parameter list.
Note: I'm talking about [pseudo-] currying, as method with multiple parameter lists (B)((B, A) => B)B becoming curried function only after eta-expansion: foldLeft _ gives B => (B,A) => B
2) haskell uses "object" of List itself as function's parameter, which allows you to do even:
Prelude> let f = foldl (\acc x -> x:acc) []
:: [a] -> [a] //here is the polymorphic function
Prelude> f [1,2,3]
[3,2,1]
Prelude> f ["1","2","3"]
["3","2","1"]
In scala you need:
scala> def f[T](x: List[T]) = x.foldLeft(List[T]()) ((acc,x) => x :: acc)
f: [T](x: List[T])List[T]
scala> f(List(1,2,3))
res3: List[Int] = List(3, 2, 1)
scala> f(List("1","2","3"))
res3: List[String] = List(3, 2, 1)
3) Finally, let's rewrite foldLeft and place monoid's 'add' and 'identity' to the same parameter list (to avoid separate inference from p.1):
def foldLeft[T, U](l: List[T])(identity: U, add: (U,T) => U) = l.foldLeft(identity)(add)
and define polymorphic add operation:
scala> def add[A](x: List[A], y: A) = y :: x
add: [A](x: List[A], y: A)List[A]
So you can:
scala> foldLeft(List(1,2,3))(Nil, add)
res63: List[Int] = List(3, 2, 1)
in comparision with:
scala> List(1,2,3).foldLeft(Nil)(add)
<console>:9: error: polymorphic expression cannot be instantiated to expected type;
found : [A, B](x: List[A], y: A)List[A]
required: (scala.collection.immutable.Nil.type, Int) => scala.collection.immutable.Nil.type
List(1,2,3).foldLeft(Nil)(add)
^
Unfortunately, scala can't infer generic type for lambdas, so you can't:
scala> foldLeft(List(1,2,3))(Nil, (acc,x) => x :: acc)
<console>:10: error: missing parameter type
foldLeft(List(1,2,3))(Nil, (acc,x) => x :: acc)
as you can't:
scala> val a = (acc,x) => x :: acc
<console>:7: error: missing parameter type
val a = (acc,x) => x :: acc
^
2 & 3) Because scala has no polymorphic lambdas at all. Can't infer A => List[A] => A (where A is a type parameter) from (acc,x) => x :: acc (even A => A from val a = (a) => a), but Haskell can:
Prelude> let lambda = \acc x -> x:acc
:: [a] -> a -> [a]
Prelude> let f = foldl(lambda) []
Prelude> f [1,2,3]
[3,2,1]
Here is an eta-expansion of perviously defined add generic method in scala:
scala> add _
res2: (List[Nothing], Nothing) => List[Nothing] = <function2>
def foldLeft[B](z: B)(f: (B, A) => B): B
Nothing is a sub-type of every other type, in this case Int. Since List() is inferred to have type List[Nothing], then f is expected to be (List[Nothing], A) => List[Nothing]
But in the function (acc, x) => x :: acc) , A is an Int, which means you should have:
(List[Nothing], Int) => List[Nothing]
When really you have:
(List[Nothing], Int) => List[Int]
And thus the type mismatch, because List[Int] can't be a List[Nothing].
This is similar to:
class A
class B extends A
scala> List.fill(5)(new A).foldLeft(List.empty[B])((acc, x) => x :: acc)
<console>:10: error: type mismatch;
found : A
required: B
List.fill(5)(new A).foldLeft(List.empty[B])((acc, x) => x :: acc)
^
The code below is based on Merge sort from "Programming Scala" causes stack overflow
def msort[T](less: (T, T) => Boolean)(xs: List[T]): List[T] = {
def merge(xs: List[T], ys: List[T], acc: List[T]): List[T] =
(xs, ys) match {
case (Nil, _) => ys.reverse ::: acc
case (_, Nil) => xs.reverse ::: acc
case (x :: xs1, y :: ys1) =>
if (less(x, y)) merge(xs1, ys, x :: acc)
else merge(xs, ys1, y :: acc)
}
val n = xs.length / 2
if (n == 0) xs
else {
val (ys, zs) = xs splitAt n
merge(msort(less)(ys), msort(less)(zs), Nil).reverse
}
}
When I try to invoke msort using :
val l = List(5, 2, 4, 6, 1, 3)
msort[Int](l)
I receive error :
Multiple markers at this line - type mismatch; found : List[Int] required: (Int, Int) => Boolean - type mismatch;
found : List[Int] required: (Int, Int) => Boolean - missing arguments for method msort in object mergesort; follow
this method with `_' if you want to treat it as a partially applied function
How do I invoke msort & why is a function required as part of the invocation ?
In Scala it is possible to have Multiple Parameters Lists. Your invocation only passes one argument.
The method is declared as def msort[T](less: (T, T) => Boolean)(xs: List[T]): List[T], so the first argument is of type (T, T) => Boolean, which is a function taking two parameters of type T and returning a Boolean value. You pass there a List[Int], which makes Scala complain.
Why would you like to have such a thing you may ask. Well, consider following example.
val stringSorter = msort[String]((a, b) => a.compareTo(b) < 0) _
// stringSorter: List[String] => List[String] = <function1>
val integerSorter = msort[Int]((a, b) => a < b) _
// integerSorter: List[Int] => List[Int] = <function1>
Those two invocation create two new functions taking only a single parameter - the list you want to sort. You don't have to tell it how to compare the elements, because you already did. Note you can invoke the same function with different lists as an argument.
integerSorter(List(2, 3, 1))
// res0: List[Int] = List(1, 2, 3)
integerSorter(List(2, 4, 1))
// res1: List[Int] = List(1, 2, 4)
stringSorter(List("b", "a", "c"))
res3: List[String] = List(a, b, c)
Note also that the newly created functions are type safe and following code will fail:
integerSorter(List("b", "a", "c"))
<console>:10: error: type mismatch;
found : String("b")
required: Int
integerSorter(List("b", "a", "c"))
Implicit Parameters
As the article in the link mentioned one of the reasons you may want to use Multiple Parameter Lists are implicit parameters.
When using implicit parameters, and you use the implicit keyword, it
applies to the entire parameter list. Thus, if you want only some
parameters to be implicit, you must use multiple parameter lists.
Let's modify the example code you gave us a bit to introduce a new type:
trait Comparator[T] {
def less(a: T, b: T): Boolean
}
and let's swap the parameter lists, and add implicit keyword to the second one, so now it becomes:
def msort[T](xs: List[T])(implicit c: Comparator[T]): List[T] = {
def merge(xs: List[T], ys: List[T], acc: List[T]): List[T] =
(xs, ys) match {
case (Nil, _) => ys.reverse ::: acc
case (_, Nil) => xs.reverse ::: acc
case (x :: xs1, y :: ys1) =>
if (c.less(x, y)) merge(xs1, ys, x :: acc)
else merge(xs, ys1, y :: acc)
}
val n = xs.length / 2
if (n == 0) xs
else {
val (ys, zs) = xs splitAt n
merge(msort(ys)(c), msort(zs)(c), Nil).reverse
}
}
Now you can declare implicit object which will be used in case you don't supply one, e.g.
implicit val intComparator = new Comparator[Int] { def less(a: Int, b: Int) = a < b }
msort(List(5, 3, 1, 3))
// res8: List[Int] = List(1, 3, 3, 5)
While this may not seem to be very appealing it gives you extra flexibility when designing your API. Let's assume that we have a type called CustomType. It can declare an implicit in the companion object and it will be resolved "automatically" by the compiler.
case class CustomType(ordinal: Int, name: String)
object CustomType {
implicit val customTypeComparator = new Comparator[CustomType] {
def less(a: CustomType, b: CustomType) = a.ordinal < b.ordinal
}
}
msort(List(CustomType(2, "Second"), CustomType(1, "First")))
// res11: List[CustomType] = List(CustomType(1,First), CustomType(2,Second))
def msort[T](less: (T, T) => Boolean)(xs: List[T]): List[T]
This function takes two arguments: a function less and a list xs.
How do I invoke msort?
You have to provide values for both arguments: msort(...)(...).
Why is a function required as part of the invocation?
Because the argument less is declared with function type (T, T) => Boolean.
Reading the paper on Types and Polymorphism in programming languages, i wondered is it possible to express the similar universal quantification on type members with Scala. Example from the paper:
type GenericID = ∀A.A ↦ A
Which is a type for generic identity function and the following example in their paper language Fun was correct:
value inst = fun(f: ∀a.a ↦ a) (f[Int], f[Bool])
value intId = fst(inst(id)) // return a function Int ↦ Int
Is there some way to express the similar thing in Scala?
This is not the same as type constructor type GenericId[A] = A => A, cause it's a type operation when ∀A.A ↦ A is a type for generic function
Following on from my comment above:
scala> type Gen[+_] = _ => _
defined type alias Gen
scala> def f(x: List[Int]): Gen[List[Int]] = x map (y => s"{$y!$y}")
f: (x: List[Int])Gen[List[Int]]
scala> f(List(1, 4, 9))
res0: Function1[_, Any] = List({1!1}, {4!4}, {9!9})
In other words, identity of types has not been preserved by Gen[+_] = _ => _.
Addendum
scala> type Identity[A] = A => A
defined type alias Identity
scala> def f(x: List[Int]): Identity[List[Int]] = x => x.reverse
f: (x: List[Int])List[Int] => List[Int]
scala> f(List(1, 4, 9))
res1: List[Int] => List[Int] = <function1>
scala> def g(x: List[Int]): Identity[List[Int]] = x => x map (y => s"{$y!$y}")
<console>:35: error: type mismatch;
found : List[String]
required: List[Int]
def g(x: List[Int]): Identity[List[Int]] = x => x map (y => s"{$y!$y}")
Try: type Gen[+_] = _ => _
scala> def f(x:List[Int]):Gen[List[Int]] = x.reverse
f: (x: List[Int])Gen[List[Int]]
scala> f(List(3,4))
res0: Function1[_, Any] = List(4, 3)
scala> def f(x:List[Number]):Gen[List[Number]] = x.reverse
f: (x: List[Number])Gen[List[Number]]
scala> f(List(3,4))
res1: Function1[_, Any] = List(4, 3)
What is the equivalent of Haskell's sequence in Scala? I want to turn list of options into an option of list. It should come out as None if any of the options is None.
List(Some(1), None, Some(2)).??? --> None
List(Some(1), Some(2), Some(3)).??? --> Some(List(1, 2, 3))
Scalaz defines sequence.
Here's an example:
scala> import scalaz._
import scalaz._
scala> import Scalaz._
import Scalaz._
scala> List(Some(1), None, Some(2)).sequence
res0: Option[List[Int]] = None
scala> List(some(1), some(2), some(3)).sequence
res1: Option[List[Int]] = Some(List(1, 2, 3))
Note that in the second example, you have to use Scalaz's some function to create a Some -- otherwise, the List is constructed as List[Some[Int]], which results in this error:
scala> List(Some(1), Some(2), Some(3)).sequence
<console>:14: error: could not find implicit value for parameter n: scalaz.Applicative[N]
List(Some(1), Some(2), Some(3)).sequence
The Scalaz some(a) and none functions create Some and None values of type Option[A].
If you want a solution for just List and Option rather a general monad then following will do the job,
def sequence[T](l : List[Option[T]]) =
if (l.contains(None)) None else Some(l.flatten)
REPL session,
scala> sequence(List(Some(1), None, Some(2)))
res2: Option[List[Int]] = None
scala> sequence(List(Some(1), Some(2), Some(3)))
res3: Option[List[Int]] = Some(List(1, 2, 3))
Update 20/8/2014
Just use Scalaz ...
Here is the same function as above using a combination of foldRight and map/ flatmap that only has to traverse the list once:
def sequence[A](lo: List[Option[A]]): Option[List[A]] =
lo.foldRight (Option(List[A]())) { (opt, ol) =>
ol flatMap (l => opt map (o => o::l))
}
Or, if you prefer the for comprehension version:
def sequence2[A](lo: List[Option[A]]): Option[List[A]] =
lo.foldRight (Option(List[A]())) { (opt, ol) =>
for {l <- ol; o <- opt} yield (o::l)
}
First off, I recommend that you check out the API docs for List.
As for a solution, this may not be the most graceful way to do it, but it'll work (and with no external dependencies):
// a function that checks if an option is a None
def isNone(opt:Option[_]) = opt match {
case None => true
case _ => false
}
//templated for type T so you can use whatever Options
def optionifyList[T](list:List[Option[T]]) = list.exists(isNone) match {
case true => None
case false => Some(list.flatten)
}
And a test just to be sure...
scala> val hasNone = Some(1) :: None :: Some(2) :: Nil
hasNone: List[Option[Int]] = List(Some(1), None, Some(2))
scala> val hasSome = Some(1) :: Some(2) :: Some(3) :: Nil
hasSome: List[Some[Int]] = List(Some(1), Some(2), Some(3))
scala> optionifyList(hasSome)
res2: Option[List[Int]] = Some(List(1, 2, 3))
scala> optionifyList(hasNone)
res3: Option[List[Int]] = None
Maybe this helps, as it traverses once only and use recursion
def sequence[A](a: List[Option[A]]): Option[List[A]] =
a match {
case Nil => Some(Nil)
case h :: rest => h.flatMap(x => sequence(rest).map(x :: _))
}
This is very simple with a for comprehension:
val x : Option[String] = Option("x")
val y : Option[String] = Option("y")
val z : Option[String] = None
// Result -> a: Option[List[String]] = None
val a = for {
x <- x
y <- y
z <- z
} yield List(x,y,z)
// Result -> b: Option[List[String]] = Some(List(x, y))
val b = for {
x <- x
y <- y
} yield List(x,y)
Since you need to flatten anyway, just do it first...
def sequence(lo: List[Option[A]]): Option[List[A]] = lo.flatten match {
la: List[A] if(la.length == lo.length) => Some(la)
_ => None
}
tail recursion might be quickest
I have an heterogeneous List like the following one:
val l = List(1, "One", true)
and I need to filter its objects by extracting only the ones belonging to a given Class. For this purpose I wrote a very simple method like this:
def filterByClass[A](l: List[_], c: Class[A]) =
l filter (_.asInstanceOf[AnyRef].getClass() == c)
Note that I am obliged to add the explicit conversion to AnyRef in order to avoid this compilation problem:
error: type mismatch;
found : _$1 where type _$1
required: ?{val getClass(): ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method any2stringadd in object Predef of type (x: Any)scala.runtime.StringAdd
and method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A]
are possible conversion functions from _$1 to ?{val getClass(): ?}
l filter (_.getClass() == c)
However in this way the invocation of:
filterByClass(l, classOf[String])
returns as expected:
List(One)
but of course the same doesn't work, for example, with Int since they extends Any but not AnyRef, so by invoking:
filterByClass(l, classOf[Int])
the result is just the empty List.
Is there a way to make my filterByClass method working even with Int, Boolean and all the other classes extending Any?
The collect method already does what you want. For example to collect all Ints in a collection you could write
xs collect { case x: Int => x }
This of course only works when you hardcode the type but as primitives are handled differently from reference types it is actually better to do so. You can make your life easier with some type classes:
case class Collect[A](collect: PartialFunction[Any,A])
object Collect {
implicit val collectInt: Collect[Int] = Collect[Int]({case x: Int => x})
// repeat for other primitives
// for types that extend AnyRef
implicit def collectAnyRef[A <: AnyRef](implicit mf: ClassManifest[A]) =
Collect[A]({ case x if mf.erasure.isInstance(x) => x.asInstanceOf[A] })
}
def collectInstance[A : Collect](xs: List[_ >: A]) =
xs.collect(implicitly[Collect[A]].collect)
Then you can use it without even passing a Class[A] instance:
scala> collectInstance[Int](l)
res5: List[Int] = List(1)
scala> collectInstance[String](l)
res6: List[String] = List(One)
Using isInstanceOf:
scala> val l = List(1, "One", 2)
l: List[Any] = List(1, One, 2)
scala> l . filter(_.isInstanceOf[String])
res1: List[Any] = List(One)
scala> l . filter(_.isInstanceOf[Int])
res2: List[Any] = List(1, 2)
edit:
As the OP requested, here's another version that moves the check in a method. I Couldn't find a way to use isInstanceOf and so I changed the implementation to use a ClassManifest:
def filterByClass[A](l: List[_])(implicit mf: ClassManifest[A]) =
l.filter(mf.erasure.isInstance(_))
Some usage scenarios:
scala> filterByClass[String](l)
res5: List[Any] = List(One)
scala> filterByClass[java.lang.Integer](l)
res6: List[Any] = List(1, 2)
scala> filterByClass[Int](l)
res7: List[Any] = List()
As can be seen above, this solution doesn't work with Scala's Int type.
The class of an element in a List[Any] is never classOf[Int], so this is behaving as expected. Your assumptions apparently leave this unexpected, but it's hard to give you a better way because the right way is "don't do that."
What do you think can be said about the classes of the members of a heterogenous list? Maybe this is illustrative. I'm curious how you think java does it better.
scala> def f[T: Manifest](xs: List[T]) = println(manifest[T] + ", " + manifest[T].erasure)
f: [T](xs: List[T])(implicit evidence$1: Manifest[T])Unit
scala> f(List(1))
Int, int
scala> f(List(1, true))
AnyVal, class java.lang.Object
scala> f(List(1, "One", true))
Any, class java.lang.Object
This worked for me. Is this what you want?
scala> val l = List(1, "One", true)
l: List[Any] = List(1, One, true)
scala> l filter { case x: String => true; case _ => false }
res0: List[Any] = List(One)
scala> l filter { case x: Int => true; case _ => false }
res1: List[Any] = List(1)
scala> l filter { case x: Boolean => true; case _ => false }
res2: List[Any] = List(true)
Despite my solution could be less elegant than this one I find mine quicker and easier. I just defined a method like this:
private def normalizeClass(c: Class[_]): Class[_] =
if (classOf[AnyRef].isAssignableFrom((c))) c
else if (c == classOf[Int]) classOf[java.lang.Integer]
// Add all other primitive types
else classOf[java.lang.Boolean]
So by using it in my former filterByClass method as it follows:
def filterByClass[A](l: List[_], c: Class[A]) =
l filter (normalizeClass(c).isInstance(_))
the invocation of:
filterByClass(List(1, "One", false), classOf[Int])
just returns
List(1)
as expected.
At the end, this problem reduces to find a map between a primitive and the corresponding boxed type.
Maybe a help can arrive from scala.reflect.Invocation (not included in the final version of 2.8.0), the getAnyValClass function in particular (here slightly edited)
def getAnyValClass(x: Any): java.lang.Class[_] = x match {
case _: Byte => classOf[Byte]
case _: Short => classOf[Short]
case _: Int => classOf[Int]
case _: Long => classOf[Long]
case _: Float => classOf[Float]
case _: Double => classOf[Double]
case _: Char => classOf[Char]
case _: Boolean => classOf[Boolean]
case _: Unit => classOf[Unit]
case x#_ => x.asInstanceOf[AnyRef].getClass
}
With this function the filter is as easy as
def filterByClass[T: Manifest](l:List[Any]) = {
l filter (getAnyValClass(_) == manifest[T].erasure)
}
and the invocation is:
filterByClass[Int](List(1,"one",true))