Why can't I call function on companion object? - scala

In the code below, why can't I call the sum function when I create an instance of fpinscala.datastructures.List? I.e. in the SBT console I do the following:
scala> :paste -raw exercises/src/main/scala/fpinscala/datastructures/List.scala
scala> val list = fpinscala.datastructures.List(2,3)
scala> list.sum(fpinscala.datastructures.List(2,3))
I guess my problem is I don't really understand the companion object - although my understanding was that it just defined functions on the type I have created which I could then call?
package fpinscala.datastructures
sealed trait List[+A] // `List` data type, parameterized on a type, `A`
case object Nil extends List[Nothing] // A `List` data constructor representing the empty list
/* Another data constructor, representing nonempty lists. Note that `tail` is another `List[A]`,
which may be `Nil` or another `Cons`.
*/
case class Cons[+A](head: A, tail: List[A]) extends List[A]
object List { // `List` companion object. Contains functions for creating and working with lists.
def sum(ints: List[Int]): Int = ints match { // A function that uses pattern matching to add up a list of integers
case Nil => 0 // The sum of the empty list is 0.
case Cons(x,xs) => x + sum(xs) // The sum of a list starting with `x` is `x` plus the sum of the rest of the list.
}
def product(ds: List[Double]): Double = ds match {
case Nil => 1.0
case Cons(0.0, _) => 0.0
case Cons(x,xs) => x * product(xs)
}
def apply[A](as: A*): List[A] = // Variadic function syntax
if (as.isEmpty) Nil
else Cons(as.head, apply(as.tail: _*))
}
EDIT: Maybe a better question is, how would I implement the following:
scala> val list = fpinscala.datastructures.List(2,3)
scala> list.sum (should return 5)

First, note that this line:
val list = fpinscala.datastructures.List(2,3)
is the same as the following:
val list = fpinscala.datastructures.List.apply(2,3)
In other words, you are calling the method apply in the List object. The return type of the apply method is the trait List, so the type of the val list is the trait List.
This means that when you call list.sum, you're trying to call the sum method of the trait List. But your trait List does not have a sum method, so it fails.
You have put the sum method in the companion object of trait List - you should put it in the trait instead (removing the parameter; or call the sum in the List object, passing list as the argument, as Seth Tisue noted in his comment).
A trait or class does not automatically have all the methods of its companion object.

Answering question about how to implement list.sum: you should define method in your List trait. Take a look at scala.collection.TraversableOnce 'sum' implementation:
def sum[B >: A](implicit num: Numeric[B]): B = foldLeft(num.zero)(num.plus)
So far List has arbitrary type, implicit instance of Numeric monoid is required - it gives zero value and operation (plus in the case of sum)

Related

Nil:List[Int] as parameter

I have following trait definition:
sealed trait List[+A]
// `List` data type, parameterized on a type, `A`
case object Nil extends List[Nothing]
// A `List` data constructor representing the empty list
/* Another data constructor, representing nonempty lists. Note that `tail` is another `List[A]`,
which may be `Nil` or another `Cons`.
*/
case class Cons[+A](head: A, tail: List[A]) extends List[A]
and a function:
def add1(l: List[Int]): List[Int] =
foldRight(l, Nil:List[Int])((h,t) => Cons(h+1,t))
My question is, what does Nil:List[Int] mean? Does it mean, I pass a Nil list with type with Int notation?
As fold (and it variants) is determining the type parameter based on the first parameter list, you cannot simply pass Nil, as the type would be derived as List[Nothing] (you would also see the second parameter list not matching). You can use type ascription to tell the Nil is of type List[Int]. You could also pass the List[Int] as the type parameter:
foldRight[List[Int]](l, Nil)((h,t) => Cons(h+1,t))
For the reference, foldRight signature is this:
def foldRight[B](z: B)(op: (A, B) => B): B

Creating own List replica in Scala

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
}

Restricting a method to a subset of values of the caller's type parameter

Summary: I want to add an instance method to instances of a parametrized type, but only for some values of the type parameter. Specifically, I have List[E], but I only want instances of List[List[_]] to have a flatten() method.
I am learning the basics of Scala and functional programming by following along with the exercises in Functional Programming in Scala by Chiusano & Bjarnason.
Suppose I have a type List[E] and a companion object List that has methods for working with instances of List[E].
sealed trait List[+E]
case object Nil extends List[Nothing]
case class Cons[+E](head: E, tail: List[E]) extends List[E]
object List {
def flatten[E](aListOfLists: List[List[E]]): List[E] = Nil
def foldLeft[E, F](aList: List[E])(acc: F)(f: (F, E) ⇒ F): F = acc
}
Now suppose I want to create analogous methods on List instances that simply forward the calls to the companion object. I would try to augment the trait definition as follows.
sealed trait List[+E] {
def foldLeft[F](acc: F)(f: (F, E) => F) = List.foldLeft(this)(acc)(f)
}
I run into a complication: List.foldLeft() works with any List[E], but List.flatten() expects a List[List[E]] argument. Thus, I only want instances of List[List[_]] to have this method. How can I add flatten() to the appropriate subset of List instances? How do I use Scala's type system to express this restriction?
We can build up what we need piece by piece. First we know that we need a type parameter for our flatten, since we don't otherwise have a way to refer to the inner element type:
sealed trait List[+E] {
def flatten[I] // ???
}
Next we need some way of establishing that our E is List[I]. We can't add constraints to E itself, since in many cases it won't be List[I] for any I, but we can require implicit evidence that this relationship must hold if we want to be able to call flatten:
sealed trait List[+E] {
def flatten[I](implicit ev: E <:< List[I]) = ???
}
Note that for reasons related to variance (and type inference) we need to use <:< instead of =:=.
Next we can add the return type, which we know must be List[I]:
sealed trait List[+E] {
def flatten[I](implicit ev: E <:< List[I]): List[I] = ???
}
Now we want to be able to call List.flatten on a List[List[I]]. Our ev allows us to convert values of type E into List[I], but we don't have E values, we just have a List[E]. There are a number of ways you could fix this, but I'll just go ahead and define a map method and use that:
sealed trait List[+E] {
def map[B](f: E => B): List[B] = this match {
case Nil => Nil
case Cons(h, t) => Cons(f(h), t.map(f))
}
def flatten[I](implicit ev: E <:< List[I]): List[I] = List.flatten(map(ev))
}
And then:
val l1 = Cons(1, Cons(2, Nil))
val l2 = Cons(3, Cons(4, Cons(5, Nil)))
val nested = Cons(l1, Cons(l2, Nil))
val flattened: List[Int] = nested.flatten
This won't actually work, since your List.flatten is broken, but it should when you fix it.

Creating Objects from type alias in Scala [duplicate]

This question already has an answer here:
Creating an object from a type parameter in Scala
(1 answer)
Closed 2 years ago.
How can one construct an object from a type alias in scala?
type MyType = List[Int]
println(List[Int]())
println(MyType()) // error: not found: value MyType
This is problematic in a function that must return a new instance of that type. Basic Example:
def foo(x: MyType): MyType = {
if (x.head == 0) MyType() // Should Nil be used?
else if (x.head == -1) new MyType(1,2,3,4)
else x
}
How can foo become unaware of the actual type of MyType?
Scala (like Java) has different namespaces for types and values, and a type alias only introduces the alias into the type namespace. In some cases you can pair the alias with a val referring to the companion object to get the effect you're looking for:
scala> case class Foo(i: Int)
defined class Foo
scala> type MyType = Foo
defined type alias MyType
scala> val MyType = Foo
MyType: Foo.type = Foo
scala> MyType(1)
res0: Foo = Foo(1)
This won't work with List[Int], though, since while both the List type and the List companion object's apply method have a type parameter, the List companion object itself doesn't.
Your best bet is to use something like Nil: MyType, but you'll find that in general using type aliases like this (i.e. just as a kind of abbreviation) often isn't the best solution.
A type is just a type, not any information about how to create instances of that.
You would have to provide it with a function that constructs an instance of the alias.
So for example
def foo(x: MyType)(create: List[Int] => MyType) =
if (x.head == 0) create(Nil) // Should Nil be used?
else if (x.head == -1) create(List(1,2,3,4))
else x
But as Erik says, it sounds like you are doing something a bit backwards.
It looks to me you're trying to achieve something with the wrong set of tools. But in any case there is no way to instantiate a type alias.
Is your goal to make the function work on a set of different collection types as opposed to only Lists? In that case you need more than just nominal decoupling; currently the function still relies on the method signatures of List.
You can decouple your function from the interface of List by using type classes, but you'll have to wrap every method call you'll ever want to make in MyOps:
import scala.language.higherKinds
import scala.reflect.ClassTag
trait MyOps[L[_], T] {
def head(xs: L[T]): T
def tail(xs: L[T]): L[T]
def fromList(xs: List[T])(implicit ev: ClassTag[T]): L[T]
}
implicit def listMyOps[T] = new MyOps[List, T] {
def head(xs: List[T]) = xs.head
def tail(xs: List[T]) = xs.tail
def fromList(xs: List[T])(implicit ev: ClassTag[T]) = xs
}
implicit def arrayMyOps[T] = new MyOps[Array, T] {
def head(xs: Array[T]) = xs(0)
def tail(xs: Array[T]) = xs.slice(1, xs.size)
def fromList(xs: List[T])(implicit ev: ClassTag[T]) = xs.toArray
}
def foo[L[_]](xs: L[Int])(implicit ev: MyOps[L, Int]) = {
ev.fromList(xs = if (ev.head(xs) == -1) List(1, 2, 3) else Nil)
}
println(foo(List(0, 1, 2, 6)))
println(foo(Array(-1, 6, 8)))
outputs:
List()
[I#54b63af0
— the first foo call takes a List and returns a List; the 2nd one Array and Array respectively.
In the world of Scala Collections for every collection type there exists a companion object that helps make it easier to construct instances of the collection.
For simplicity consider this class and object of the same name:
object Numeric {
def apply(s: String): Numeric = new Numeric(s.toDouble)
}
case class Numeric(v: Double)
If you only had the case class then writing Numeric("5.1") would be erroneous. With the object you can actually now call Numeric.apply("5.1") or (because apply is a special method) you can simply write Numeric("5.1"). object in Scala is analogous to holding all static methods that you would write in Java.
Back to your example, MyType is only the type alias to List[Int] and does not bring the List companion object into scope with the name MyType. Your example is the equivalent of my Numeric example without the companion object.
Thus, my answer, is to create a simple and generic way to construct your companion object that hides the fact that 1) MyType is an alias and 2) that it restricts the collection type to Int. If you have lots of type aliases like this one in your code then you'll probably want the more generic version here:
import scala.collection.GenTraversable
import scala.collection.generic.GenericCompanion
class TypeCompanion[CC[X] <: GenTraversable[X], T](companion: GenericCompanion[CC]) {
type InnerType = CC[T]
def apply(elems: T*): InnerType = companion.apply(elems: _*)
def empty(): InnerType = companion.empty[T]
}
object MyType extends TypeCompanion[List, Int](List)
type MyType = MyType.InnerType
If you want to reduce the number of times that you write List, and will not mind the extra typing if you need to change from Int to some other type, then you may prefer this variation:
class TypeCompanion[CC[X] <: GenTraversable[X]](companion: GenericCompanion[CC]) {
type InnerType = CC[Int]
def apply(elems: Int*): InnerType = companion.apply(elems: _*)
...
}
object MyType extends TypeCompanion(List)
type MyType = MyType.InnerType
Both implementations give your foo method this implementation:
def foo(x: MyType): MyType = {
if (x.head == 0) MyType()
else if (x.head == -1) MyType(1,2,3,4)
else x
}
Note that the type restrictions on GenTraversable and GenericCompanion are just a clever way of restricting to companion objects that match scala collection's conventions.

Why is there no Tuple1 Literal for single element tuples in Scala?

Python has (1,) for a single element tuple. In Scala, (1,2) works for Tuple2(1,2) but we must use Tuple1(1) to get a single element tuple. This may seem like a small issue but designing APIs that expect a Product is a pain to deal for users that are passing single elements since they have to write Tuple1(1).
Maybe this is a small issue, but a major selling point of Scala is more typing with less typing. But in this case it seems it's more typing with more typing.
Please tell me:
1) I've missed this and it exists in another form, or
2) It will be added to a future version of the language (and they'll accept patches).
You can define an implicit conversion:
implicit def value2tuple[T](x: T): Tuple1[T] = Tuple1(x)
The implicit conversion will only apply if the argument's static type does not already conform to the method parameter's type. Assuming your method takes a Product argument
def m(v: Product) = // ...
the conversion will apply to a non-product value but will not apply to a Tuple2, for example. Warning: all case classes extend the Product trait, so the conversion will not apply to them either. Instead, the product elements will be the constructor parameters of the case class.
Product is the least upper bound of the TupleX classes, but you can use a type class if you want to apply the implicit Tuple1 conversion to all non-tuples:
// given a Tupleable[T], you can call apply to convert T to a Product
sealed abstract class Tupleable[T] extends (T => Product)
sealed class ValueTupler[T] extends Tupleable[T] {
def apply(x: T) = Tuple1(x)
}
sealed class TupleTupler[T <: Product] extends Tupleable[T] {
def apply(x: T) = x
}
// implicit conversions
trait LowPriorityTuple {
// this provides a Tupleable[T] for any type T, but is the
// lowest priority conversion
implicit def anyIsTupleable[T]: Tupleable[T] = new ValueTupler
}
object Tupleable extends LowPriorityTuple {
implicit def tuple2isTuple[T1, T2]: Tupleable[Tuple2[T1,T2]] = new TupleTupler
implicit def tuple3isTuple[T1, T2, T3]: Tupleable[Tuple3[T1,T2,T3]] = new TupleTupler
// ... etc ...
}
You can use this type class in your API as follows:
def m[T: Tupleable](v: T) = {
val p = implicitly[Tupleable[T]](v)
// ... do something with p
}
If you have your method return the product, you can see how the conversions are being applied:
scala> def m[T: Tupleable](v: T) = implicitly[Tupleable[T]](v)
m: [T](v: T)(implicit evidence$1: Tupleable[T])Product
scala> m("asdf") // as Tuple1
res12: Product = (asdf,)
scala> m(Person("a", "n")) // also as Tuple1, *not* as (String, String)
res13: Product = (Person(a,n),)
scala> m((1,2)) // as Tuple2
res14: Product = (1,2)
You could, of course, add an implicit conversion to your API:
implicit def value2tuple[A](x: A) = Tuple1(x)
I do find it odd that Tuple1.toString includes the trailing comma:
scala> Tuple1(1)
res0: (Int,) = (1,)
Python is not statically typed, so tuples there act more like fixed-size collections. That is not true of Scala, where each element of a tuple has a distinct type. Tuples, in Scala, doesn't have the same uses as in Python.