I'm learning Scala and in a book that I'm reading (Functional Programming in Scala) I came across an example of a custom List implementation in Scala which goes like this:
sealed trait MyList[+A]
case object MyNil extends MyList[Nothing]
case class Cons[+A](head: A, tail: MyList[A]) extends MyList[A]
object MyList {
def apply[A](as: A*): MyList[A] =
if (as.isEmpty) MyNil
else Cons(as.head, apply(as. tail: _*))
}
I would like to extend MyList to add the following functionality:
add a tail method that returns all elements of a MyList instance without the first one, e.g. val x = MyList(1,2,3); x.tail == MyList(2,3).
Add a sum method that is only applicable when MyList contains Ints (or even better for all numeric types). So e.g. val x = MyList(1,2,3); x.sum == 6
The idea above 2 questions is to understand: (1) how to interact with the instance of my class and (2) how to use polymorphism in a situation like this. After some searching around, I'm not even sure how to begin with these problems, which is why I'm asking this question.
Any tips would be appreciated. Many thanks!
UPDATE:
A few updates:
First, I'd like to point out that the solution to the programming challenges in the Functional Programming course that I mentioned earlier can be found here, however, I'm looking for something a little different than what the author is asking for.
I've managed to find an answer to my first question "how can I use tail on my instance itself, e.g. MyList(1,2,3).tail?". To solve this, I had to modify the original trait in the following manner:
sealed trait MyList[+A] {
def tail: MyList[A] = MyList.tail(this)
}
I'm not sure if this is the best way of doing what I want to do, but it works. If anyone has better suggestions, please let me know.
The second part is harder. I wanted to add the following inside the same trait:
def sum[Int]: MyList[Int] = MyList.sum(this)
But IntelliJ is complaining about the type of this which is A and I need to apply this conditionally on this being of type Int.
Another alternative is to do the following:
def sum: Int = this match {
case x: MyList[Int] => MyList.sum(x)
}
But what if we want to create another implementation for String that will also return a String? This cannot be the right solution and I haven't found one yet. Please help :)
.tail
I note that your Cons class already has a public tail member. I'd be tempted to start there and just make it universal...
sealed trait MyList[+A] {
def tail: MyList[A]
}
...and add the MyNil implementation.
case object MyNil extends MyList[Nothing] {
def tail: MyList[Nothing] =
throw new java.lang.UnsupportedOperationException("tail of empty list")
}
This is how the standard library List handles the tail of an empty list. Another, perhaps gentler, option would be to return this so that the tail of an empty MyList is just the empty MyList.
Leaving class Cons and object MyList unchanged, we get the expected results.
MyList('s','h','o','w').tail //res0: MyList[Char] = Cons(h,Cons(o,Cons(w,MyNil)))
MyList(9).tail.tail //java.lang.Unsupported...
.sum
This is a bit trickier. We want each .sum invocation to compile only if the elements are of a sum-able type, such as Int. The Scala way to achieve this to require that the call site provide implicit "evidence" that the element type is acceptable.
sealed trait MyList[+A] {
def sum(implicit ev : A =:= Int) : Int //can sum only if A is Int
}
Alas, this won't compile because MyList is covariant on A, but being the type of a passed parameter puts A in a contra-variant position.
Error: covariant type A occurs in invariant position in type A =:= Int of value ev
Fortunately there's a fix for that: use a different type parameter, related to A but not restricted to its covariant relationship.
sealed trait MyList[+A] {
def sum[B >: A](implicit ev : B =:= Int) : Int = 0 //default behavior
}
case object MyNil extends MyList[Nothing] { ... //unchanged
case class Cons[+A](head: A, tail: MyList[A]) extends MyList[A] {
override def sum[B >: A](implicit ev :B =:= Int) : Int = head + tail.sum[B]
}
object MyList { ... //unchanged
MyList(23,31,12).sum //res0: Int = 66
MyList("as","is").sum //won't compile
Numeric[A]
Well that works for Int, but it would be a pain to have to do the same for every sum-able type. Fortunately the standard library offers the Numeric typeclass which provides some basic values (zero and one) and operations (plus(), minus(), times(), etc.) for all the numeric types under its umbrella (Short, Long, Float, etc.).
So, putting it all together:
sealed trait MyList[+A] {
val tail: MyList[A]
def sum[B >: A](implicit ev : Numeric[B]): B = ev.zero
}
case object MyNil extends MyList[Nothing] {
val tail: MyList[Nothing] = this
}
case class Cons[+A](head: A, tail: MyList[A]) extends MyList[A] {
override def sum[B >: A](implicit ev : Numeric[B]): B = ev.plus(head, tail.sum[B])
}
object MyList {
def apply[A](as: A*): MyList[A] =
if (as.isEmpty) MyNil else Cons(as.head, apply(as.tail: _*))
}
Related
As I am working a design model, I am torn between two different methods of indicating a parameter of type List must be nonEmpty. I began by using List[Int] with an accompanying require statement to verify the List is nonEmpty.
case class A(name: String, favoriteNumbers: List[Int]) {
require(favoriteNumbers.nonEmpty, "favoriteNumbers must not be empty")
}
I then needed to make the list optional. If the List is provided, it must be nonEmpty. I'm using using Option[List[Int]] with an accompanying require statement to verify, if the Option is nonEmpty, the list must also be nonEmpty.
case class B(name: String, favoriteNumbers: Option[List[Int]]) {
require(
favoriteNumbers.isEmpty || favoriateNumbers.get.nonEmpty
, "when defined, favoriteNumbers.get must be nonEmpty"
)
}
However, I need to use this non-empty List all over the system I am modeling. This means that my code has these same require statements duplicated everywhere. Is there a (non-ScalaZ) way to have a new type, say NeList, which is defined and behaves identically to List, with the only change being an exception is thrown when NeList attempts to be instantiated with no elements?
I tried to Google for this and couldn't find a set of search terms to hone on this area. I either got really simple List how-tos, or all sorts of references to ScalaZ's NEL (Non Empty List). So, if there is a link out there that would help with this, I would love to see it.
If you
def foo[A](x: ::[A]) = "List has length "+x.length
then you insist that the list be nonempty. But of course your lists are all typed as List, so you need a helper method to give you a nonempty list:
implicit class NonEmptyList[A](private val underlying: List[A]) {
def ifNonEmpty[B](f: ::[A] => B): Option[B] = {
underlying match {
case x: ::[A #unchecked] => Some(f(x))
case _ => None
}
}
}
Now you can safely apply the operation to get an Option out. (You could also run side-effecting functions in a foreach-like method.)
Now, this is rather non-idiomatic Scala. But it is safe at compile time (the #unchecked notwithstanding--Scala's compiler isn't quite smart enough to realize that the type parameter hasn't changed).
You could implement a non-empty list yourself with implicit conversions between List[A] and Nel[A]:
case class Nel[A](val head: A, val tail: List[A] = Nil)
implicit def list2Nel[A](list: List[A]): Nel[A] = {
require(!list.isEmpty)
Nel(list.head, list.tail)
}
implicit def nel2List[A](nel: Nel[A]): List[A] = nel.head :: nel.tail
Then you can define your functions where this is needed such that they take a Nel[A] as a parameter:
def f(l: Option[Nel[String]]) = { ... }
And call them with normal lists (assuming the implicit defs are in scope):
f(Some(List("hello", "world")) // works
f(Some(Nil)) // throws IllegalArgumentException
f(None) // works
EDIT: It should be noted that this does not provide compile time guarantees that the List[A] passed in will not be empty. If that's what you want, then get rid of the implicit def list2Nel and require clients of your function to pass in an Nel[A] explicitly, thus guaranteeing at compile time that the list is not empty.
Also, this is a very basic NonEmptyList implementation. A more complete solution is found in scalaz (granted it was specifically requested in the question that scalaz not be used): https://github.com/scalaz/scalaz/blob/series/7.2.x/core/src/main/scala/scalaz/NonEmptyList.scala
I'm coming from C++ and trying to wrap my head around scala's type system.
Consider the following C++ template class:
template<class T>
class Point2
{
Point2( T x, T y ) :
x(x),
y(y)
{}
T x;
T y;
Point2<T> operator+( Point<T> const& other ) const
{
return Point<T>(x+other.x, y+other.y);
}
T sumComponents() const { return x+y; }
}
Point2<Double> p0(12.3, 45.6)
Point2<Double> p1(12.3, 45.6)
Point2<Double> p = p1+p2
Double d = p1.sumComponents()
I'm finding I want to write something like this:
case class Point2[ T ] (x:T, y:T) {
def +() Point2[T]: = x+y
def sumComponents() T: = x+y
}
or, (because the compile has problems with this),
trait Addable[T] { // Require T supports the + operatory
def +( that:T ):T
}
case class Point2[ T<:Addable[T] ] (x:T, y:T) {
def +() Point2[T]: = x+y
def sumComponents() T: = x+y
}
which is similarly problematic because I can't require Double to extend Addable.
Generally, I'm finding it scala's type system works with a set of constraints that I don't quite understand.
What's the idiomatic way of implementing the above in scala?
And what's the right way for C++ template programmers to understand the limits of generics in scala? (why can't I do this in scala? e.g. Is it because generics are compiled before being instaniated?)
What's the idiomatic way of implementing the above in scala?
Either by specifying appropriate requirements of T, or using type classes to provide the desired behavior. I'll get back to this later.
And what's the right way for C++ template programmers to understand
the limits of generics in scala? (why can't I do this in scala? e.g.
Is it because generics are compiled before being instaniated?)
C++ templates are compiled "at" the usage site, and different code is generated for each combination of parameters to the templates. So if you use the class above with int and double, you get two different Point2 classes compiled.
Basically, C++ templates are macros, though nowhere near as dumb as #define macros. In fact, C++ templates are turing complete. Maybe it will be possible to accomplish something equivalent in the future, with the upcoming macro capabilities planned for Scala 2.11 and beyond, but let's ignore that for now.
Type parameters (Scala equivalent of Java generics) do not change how a code is compiled. A parameterized class generates its bytecode when it is compiled, not when it is used. So, by the time one instantiates a Point2 with Double, it is too late to generate bytecode.
That means that the code generated by a parameterized class must be compatible with all types a class can be instantiated with.
And that's the source of the trouble: any methods called on T must be known to be present on T at the time Point2 is compiled. Therefore, T must be defined to have an upper boundary of traits or classes that define such methods, as you have shown in your example.
Of course, that is not always possible, as you rightly pointed out, and that's where type classes come in. A type class is a set of types for which a set of behaviors is defined. Type classes, as implemented in Scala, are defined as classes whose instances define the behavior of other classes.
In the example you gave, you'd be using either the Numeric type class, or the Fractional type class if you need fractional division as well. A simple example of type class use is:
scala> import scala.math.Numeric
import scala.math.Numeric
scala> def sum[T](x: T, y: T)(implicit num: Numeric[T]): T = num.plus(x, y)
sum: [T](x: T, y: T)(implicit num: scala.math.Numeric[T])T
Or, using a special notation called "context bounds",
scala> def sum[T : Numeric](x: T, y: T): T = implicitly[Numeric[T]].plus(x, y)
sum: [T](x: T, y: T)(implicit evidence$1: scala.math.Numeric[T])T
The notation T : Numeric can be read as T such that there's an implicit instance of Numeric[T] available. The code implicitly[X] returns an implicit value of type X if one can be found (or fails at compile time).
Now, notice how no method is called on x and y -- instead, we call methods on num whose class is Numeric[T]. The class Numeric[T] has a method plus which knows how to add two Ts.
Because what we need is type class instances, one can easily add new types to satisfy a type class. One could easily declare a Numeric type class for Point2 (assuming all its methods could be implemented):
class Point2Numeric[T](implicit num: Numeric[T]) extends Numeric[Point2[T]] {
def plus(x: Point2[T], y: Point2[T]): Point2[T] = x + y
// etc
}
implicit def ToPoint2Numeric[T : Numeric] = new Point2Numeric[T]
With that in place, then for any T for which there's a Numeric[T], there would be also a Numeric[Point2[T]].
After plain type inheritance (upper type bounds), type classes are the most common form of type constraint used in Scala. There are other forms a bit more sophisticated, for which there's some discussion whether they are type classes or something different -- the magnet pattern, for instance. Look at shapeless for an example of how far one can take such things.
Another kind of type constraint that used to be very common but is now being used more circumspectly are view bounds. I'll not go into details (in fact, search for context bounds and view bounds to find a long answer about it from myself), but they can be used to make type classes more readable when used. For example:
scala> import scala.math.Numeric.Implicits._
import scala.math.Numeric.Implicits._
scala> def sum[T : Numeric](x: T, y: T): T = x + y
sum: [T](x: T, y: T)(implicit evidence$1: scala.math.Numeric[T])T
The imported definitions contain implicit conversions that make it possible to use values of type T for which there's a Numeric[T] as if they, themselves, had the methods like + or -.
As a final note, it is important to realize this goes through many levels of indirection and, therefore, might not be very suitable for high performance code.
Simply, you can do something like this:
scala> :paste
// Entering paste mode (ctrl-D to finish)
import math.Numeric
import math.Numeric.Implicits._
case class Point2[A: Numeric](x: A, y: A) {
def + (other: Point2[A]): Point2[A] =
Point2(this.x + other.x, this.y + other.y)
def sumComponents: A = x + y
}
// Exiting paste mode, now interpreting.
import math.Numeric
import math.Numeric.Implicits._
defined class Point2
scala> val p1 = Point2(1, 2)
p1: Point2[Int] = Point2(1,2)
scala> val p2 = Point2(3, 4)
p2: Point2[Int] = Point2(3,4)
scala> p1 + p2
res2: Point2[Int] = Point2(4,6)
scala> val p3 = Point2(1.2, 3.4)
p3: Point2[Double] = Point2(1.2,3.4)
scala> val p4 = Point2(1.6, 6.4)
p4: Point2[Double] = Point2(1.6,6.4)
scala> p3 + p4
res3: Point2[Double] = Point2(2.8,9.8)
scala>
I created a library template.scala. You can use the library to create C++ flavored templates, avoiding complicated implicits.
import com.thoughtworks.template
case class Point2[T](x:T, y:T) {
#template def +(rhs: Point2[_]) = Point2(x + rhs.x, y + rhs.y)
#template def sumComponents() = x + y
}
println(Point2(1, 3).sumComponents()) // Output: 4
println(Point2(1, 3) + Point2(100, 200)) // Output: Point2(101,203)
Note that you can even plus two Point2s with different component types.
println(Point2(1.5, 0.3) + Point2(100, 200)) // Output: Point2(101.5,200.3)
Even nested Point2:
// Output: Point2(Point2(10.1,20.2),Point2(101.0,202.0))
println(Point2(Point2(0.1, 0.2), Point2(1.0, 2.0)) + Point2(Point2(10, 20), Point2(100, 200)))
It works because #template functions are code templates that will inline at the call site.
This requires a type class (which I'm calling Addition) and an implicit conversion (which I'm defining via an implicit class called Op). In practice, you would use the Numeric type for this particular situation, but for the purpose of illustration, this is how you would define your own:
trait Addition[T] {
def add(a: T, b: T): T
implicit class Op(a: T) {
def +(b: T) = add(a, b)
}
}
implicit object IntAddition extends Addition[Int] {
def add(a: Int, b: Int) = a + b
}
implicit object DoubleAddition extends Addition[Double] {
def add(a: Double, b: Double) = a + b
}
case class Point2[T](x: T, y: T)(implicit addition: Addition[T]) {
import addition.Op
def +(p: Point2[T]): Point2[T] = Point2(x + p.x, y + p.y)
def sumComponents(): T = x + y
}
Use Numeric, available as an implicit.
import scala.math.Numeric;
case class Point2[T](x: T, y: T)(implicit num: Numeric[T])
Look at Numeric in the API, does what you need.
I'm trying to get my head around the covariance of Scala's collections. I have the following:
abstract class MediaFormat{
def name:String
def status:String
}
case class H264_high(status:String="on") extends MediaFormat {
def name = "h264_high"
}
case class H264_med(status:String="on") extends MediaFormat {
def name = "h264_med"
}
case class H264_low(status:String="on") extends MediaFormat {
def name = "h264_low"
}
case class H264_syndication(status:String="off") extends MediaFormat {
def name = "h264_syndication"
}
What I wanted to do was have a set of all of these formats because I need a collection where each format only occurs once, so I tried:
object MediaFormat {
val allFormats:Set[MediaFormat] = Set(H264_high,H264_low)
}
This gave me a compile time exception because, as I now understand, Set is invariant.
So I think, well I guess I'll just have to use a List and manage the repeated values myself
but then I try this:
object MediaFormat {
val allFormats:List[MediaFormat] = List(H264_high,H264_low)
}
because as I understand it, List is covariant, but that still doesn't compile.
Can someone help me understand what I should do to get a collection of my formats?
It doesn't compile because you are referencing the companion object (module), not the case classes! The compile error (which you should have posted) is nothing to do with variance. It will work, with Set if you do this:
val allFormats: Set[MediaFormat] = Set(H264_high(), H264_low())
^^ ^^
Or alternatively;
val allFormats = Set[MediaFormat](H264_high(), H264_low())
However, it makes no sense for these to be case classes given your description of the problem; I would just make them modules, i.e.
case object H264_syndication extends MediaFormat {
def status = "off"
def name = "h264_syndication"
}
Then your original code will work just fine. Or I would make them vals as follows:
case class MediaFormat(status: String, name: String)
val H264_syndication = MediaFormat(status ="off", name = "h264_syndication")
I think this would be my preference; I rarely use abstract classes any more to be honest (normally, I am dishonest).
Explanation: Covariance means the following:
G[S] <: G[T] iff S <: T
The fact that Set is invariant, means that a Set[S] is not a subtype of Set[T] (for S <: T), but it does not mean that such a Set[T] may not contain elements of type S.
Say I'm defining a simple 2D point class in Scala, and I want to be able to construct it with various types:
class Point(x:Float, y:Float) {
this(x:Double, y:Double) = this(x.toFloat, y.toFloat)
this(x:Int, y:Int) = this(x.toFloat, y.toFloat)
// etc...
}
I want to boil this down using a template, such as:
class Point(x:Float, y:Float) {
this[T](x:T, y:T) = this(x.toFloat, y.toFloat)
}
I know this won't work anyway, since T could be a type for which toFloat isn't defined, but the compiler error I get is:
no type parameters allowed here
Is this just unsupported in Scala? If so, why, and is there any simple way to get around this?
Scala's class constructors (unlike Java's) can't take type parameters, only the class itself can. As to why Scala made this design choice, I assume the main reason is simplicity.
If you want a secondary "builder" method that is generic, the natural thing to do is define it on the companion object. For example,
object Point {
def build[T : Numeric](x: T, y: T) = {
val n = implicitly[Numeric[T]]
new Point(n.toFloat(x), n.toFloat(y))
}
}
class Point(val x:Float, val y:Float)
val p = Point.build(1, 2) // Companion object's builder
p.x + p.y
Here I've used the Numeric typeclass to get a generic toFloat method.
I played with this for awhile, getting as "close" as...
class Point(x:Float, y:Float) {
def this[T <: Any { def toFloat: Float }](x:T, y:T) = this(x.toFloat, y.toFloat)
}
...which results in "error: no type parameters allowed here" (just as per the post) and then I realized...
If the initializer could take type parameters it would be ambiguous with the class parameters, if any. Not that this couldn't be worked about in the language specification... but it is a more complex case at the very least. There might also be Java interoperability issues.
Imagine:
class Foo[T](x: T) {
def this[X](z: X) = ...
}
new Foo[Int](42) // T is Int? X is ...? Or ...?
Personally I wish Scala followed an Eiffel-like pattern (only named constructors or "factory methods"), but alas, that would not be Scala.
Happy coding.
I am trying to create a wrapper of List with a specific type (e.g. List[Int]) such that methods that take an implicit CanBuildFrom parameter return an instance of my wrapper instead of List.
One possible solution, which feels rather heavyweight, is:
import scala.collection._
import generic.{CanBuildFrom, SeqForwarder}
import mutable.{Builder, ListBuffer}
class MyList(list: List[Int]) extends immutable.LinearSeq[Int]
with LinearSeqLike[Int, MyList]
with SeqForwarder[Int] {
override def newBuilder: Builder[Int, MyList] = MyList.newBuilder
protected override def underlying = list
}
object MyList {
def newBuilder: Builder[Int, MyList] =
new ListBuffer[Int] mapResult(new MyList(_))
implicit def canBuildFrom: CanBuildFrom[MyList, Int, MyList] = {
new CanBuildFrom[MyList, Int, MyList] {
def apply(from: MyList) = from.newBuilder
def apply() = newBuilder
}
}
}
val l1 = new MyList(List(1,2,3))
println(l1.isInstanceOf[MyList])
println(l1.map(_ + 1).isInstanceOf[MyList])
println(l1.filter(_ == 2).isInstanceOf[MyList])
Is there a better/easier way to create such a wrapper or did I miss anything important in the implementation of MyList?
Edit: A follow-up question is: Can this whole wrapper logic be put into ListWrapper classes or traits so that the above MyList can be implemented like this:
class MyList extends ListWrapper[Int, MyList]
object MyList extends ListWrapperFactory[Int, MyList]
As far I know from reading this article:
http://www.scala-lang.org/docu/files/collections-api/collections-impl.html
your solution is the simplest one, if you want filter/map/etc. to all return instances of MyList. newBuilder is needed for ops like filter, and the implicit CanBuildFrom for ops like map, which may change the collection type.
What you should maybe do in your CanBuildFrom is this:
def apply(from: MyList) = from.newBuilder // call it on `from'
which ensures that a map on a statically-typed MyList which actually has a dynamic type that is a subtype of MyList will reuse that same dynamic type.
Edit: seems like there is a little something missing, for this map returns an instance of List and not MyList:
val l1: LinearSeq[Int] = new MyList(List(1, 2, 3))
println(l1.map(_ + 1)) // prints List(2, 3, 4)
it looks like this is also the case with the RNA example taken from the linked article. If it has static type IndexedSeq[Base] instead of RNA, a map on it returns a vector.
Edit 2: looks like this is a more general problem, discussed in this question.
Regarding my follow-up question how to mixin the wrapper logic via classes or traits, this is what I came up with:
import scala.collection._
trait ListWrapper[Elem, Repr <: ListWrapper[Elem, Repr]]
extends immutable.LinearSeq[Elem]
with LinearSeqLike[Elem, Repr]
with generic.SeqForwarder[Elem] { self: Repr =>
def wrapperCompanion: ListWrapperCompanion[Elem, Repr]
override def newBuilder: mutable.Builder[Elem, Repr] =
wrapperCompanion.newBuilder
}
trait ListWrapperCompanion[Elem, Repr <: ListWrapper[Elem, Repr]] {
def apply(elems: TraversableOnce[Elem]): Repr
def newBuilder: mutable.Builder[Elem, Repr] =
new mutable.ListBuffer[Elem].mapResult(apply)
def canBuildFromWrapper: generic.CanBuildFrom[Repr, Elem, Repr] = {
new generic.CanBuildFrom[Repr, Elem, Repr] {
def apply(from: Repr) = from.newBuilder
def apply() = newBuilder
}
}
}
Now MyList can be implemented by:
class MyList(val underlying: List[Int]) extends ListWrapper[Int, MyList] {
def wrapperCompanion = MyList
}
object MyList extends ListWrapperCompanion[Int, MyList] {
def apply(elems: TraversableOnce[Int]) = new MyList(elems.toList)
implicit def canBuildFrom = canBuildFromWrapper
}
This is definitely better than having all the boilerplate code in MyList's definition, but it is still a lot to write for making MyList just a wrapper for List.