Nick says:
In this function
head, it takes a list ofA’s, and returns anA. And it doesn’t matter what theAis: It could beInts,Strings,Oranges,Cars, whatever. AnyAwould work, and the function is defined for everyAthat there can be.
def head[A](xs: List[A]): A = xs(0)
head(1 :: 2 :: Nil)
// res1: Int = 1
case class Car(make: String)
head(Car("Civic") :: Car("CR-V") :: Nil)
// res2: Car = Car(make = "Civic")
Haskell wiki says:
Parametric polymorphism refers to when the type of a value contains one or more (unconstrained) type variables, so that the value may adopt any type that results from substituting those variables with concrete types.
Let’s think of a function plus that can add two values of type A:
def plus[A](a1: A, a2: A): A = ???
Depending on the type A, we need to provide different definition for what it means to add them.
One way to achieve this is through subtyping.
trait PlusIntf[A] {
def plus(a2: A): A
}
def plusBySubtype[A <: PlusIntf[A]](a1: A, a2: A): A = a1.plus(a2)
We can at least provide different definitions of plus for A.
But, this is not flexible since trait Plus needs to be mixed in at the time of defining the datatype.
So it can’t work for Int and String.
The third approach in Scala is to provide an implicit conversion or implicit parameters for the trait.
trait CanPlus[A] {
def plus(a1: A, a2: A): A
}
def plus[A: CanPlus](a1: A, a2: A): A = implicitly[CanPlus[A]].plus(a1, a2)
This is truely ad-hoc in the sense that
A
Int) without access to its source code
The last point makes Scala’s ad-hoc polymorphism more powerful than that of Haskell. More on this topic can be found at Debasish Ghosh @debasishg’s Scala Implicits : Type Classes Here I Come.
Let’s look into plus function in more detail.