So, I have been searching documentation about the main difference between parametric polymorphism and adhoc-polymorphism, but I still have some doubts.
For instance, methods like head in Collections, are clearly parametric polymorphism, since the code used to obtain the head in a List[Int] is the same as in any other List.
List[T] {
def head: T = this match {
case x :: xs => x
case Nil => throw new RuntimeException("Head of empty List.")
}
}
(Not sure if that's the actual implementation of head, but it doesn't matter)
On the other hand, type classes are considered adhoc-polymorphism. Since we can provide different implementations, bounded to the types.
trait Expression[T] {
def evaluate(expr: T): Int
}
object ExpressionEvaluator {
def evaluate[T: Expression](value: T): Int = implicitly[Expression[T]].evaluate(value)
}
implicit val intExpression: Expression[Int] = new Expression[Int] {
override def evaluate(expr: Int): Int = expr
}
ExpressionEvaluator.evaluate(5)
// 5
In the middle, we have methods like filter, that are parametrized, but we can provide different implementations, by providing different functions.
List(1,2,3).filter(_ % 2 == 0)
// List(2)
Are methods like filter, map, etc, considered ad-hoc polymorphism? Why or why not?
The method filter on Lists is an example of parametric polymorphism. The signature is
def filter(p: (A) ⇒ Boolean): List[A]
It works in exactly the same way for all types A. Since it can be parameterized by any type A, it's ordinary parametric polymorphism.
Methods like map make use of both types of polymorphism simultaneously.
Full signature of map is:
final def map[B, That]
(f: (A) ⇒ B)
(implicit bf: CanBuildFrom[List[A], B, That])
: That
This method relies on the presence of an implicit value (the CBF-gizmo), therefore it's ad-hoc polymorphism. However, some of the implicit methods that provide the CBFs of the right type are actually themselves parametrically polymorphic in types A and B. Therefore, unless the compiler manages to find some very special ad-hoc construct like an CanBuildFrom[List[String], Int, BitSet] in the implicit scope, it will sooner or later fall back to something like
implicit def ahComeOnGiveUpAndJustBuildAList[A, B]
: CanBuildFrom[List[A], B, List[B]]
Therefore, I think one could say that it's a kind-of "hybrid parametric-ad-hoc polymorphism" that first attempts to find the most appropriate ad-hoc type class CanBuildFrom[List[A], B, That] in the implicit scope, but eventually falls back to ordinary parametric polymorphism, and returns a one-fits-all CanBuildFrom[List[A], B, List[B]]-solution that is parametrically polymorphic in both A and B.
Related
Is there any sufficient difference between constraints of two method at the trait Foo?
trait Foo[A] {
def barWithTypeBound[B <: A]: B
def barWithGeneralizedTypeConstraint[B](implicit ev: B <:< A): B
}
Sometimes it is easier to produce an evidence at call site than provide the evidence through all intermediate layers, e.g.
trait Flattenable[F[_]] {
def flatten[A](ffa: F[F[A]]): F[A]
}
extension [F[_], A](fa: F[A])
def flatten[B](using A <:< F[B], F: Flattenable[F]): F[B] =
F.flatten(fa)
To implement this extension without <:< I would have to change the definition of fa:
extension [F[_], A](fa: F[F[A]])
def flatten[B](using F: Flattenable[F]): F[B] =
F.flatten(fa)
which is possible here but not in every case. Another example would be something like:
class Wrapper[A](value: A):
def get: A = value
def isNatural(using: A <:< Int): Boolean = value >= 0
def isTrue(using A <:< Boolean): Boolean = value
which allows caller to call the method only of A is of particular type. (But again, you could solve these with specialized extension methods and normal constraints). I was able to define parametric type in one place, and slap an additional constraint on it later on. If I would need that constrain from the start, I would just use a type bound.
Usually, there is no need to make some method (or implicit, or given) available or not based on the type. And it only proves that some particular case is true, so it wouldn't work well with co- and contravatiance. And, it requires you to create a dummy object. So with exception of a few cases where such "hack" is useful normal constrains are preferred.
In your example there is no difference between the 2 methods, except the second one would have to pass and additional object as a parameter.
What's the point of using a typeclass over inheritance?
This is a function that uses the Monad typeclass by a context bound:
def f[A : Monad](x:A) = ???
( Yeah, we get flatMap method now)
This, however, uses inheritance with a subtype bound:
def f[A <: Monad](x:A) = ???
f(x) // where x is a CatsList which implements Monad trait.
( We also get flatMap method now.)
Don't both achieve the same thing?
Typeclasses are more flexible. In particular, it's possible to retrofit a typeclass to an existing type easily. To do this with inheritance, you would need to use the adapter pattern, which can get cumbersome when you have multiple traits.
For example, suppose you had two libraries which added the traits Measurable and Functor, respectively, using inheritance:
trait Measurable {
def length: Int
}
trait Functor[A] {
def map[B](f: A => B): Functor[B]
}
The first library helpfully defined an adapter for List => Measurable:
class ListIsMeasurable(ls: List[_]) extends Measurable {
def length = ls.length
}
And the second library did the same for List => Functor. Now we want to write a function that takes things that have both length and map methods:
def foo(x: Measurable with Functor) = ???
Of course, we should hope to be able to pass it a List. However, our adapters are useless here, and we have to write yet another adapter to make List conform to Measurable with Functor. In general, if you have n interfaces that might apply to List, you have 2^n possible adapters. On the other hand, if we had used typeclasses, there would have been no need for the extra boilerplate of a third typeclass instance:
def foo[A : Measurable : Functor](a: A) = ???
What you're saying is possible for the simplest cases, but type classes can give you much better flexibility in a lot of cases.
Take for example the Monoid type class:
trait Monoid[A] {
def empty: A
def combine(x: A, y: A): A
}
If you try to express the empty function with inheritance, you'll see it is pretty much impossible. That is because type classes operate on types rather than individual class instances.
Now let's define a Monoid for something like Tuple2:
implicit def tupleMonoid[A: Monoid, B: Monoid]: Monoid[(A, B)] = ...
Now you're in a territory where inheritance can't get you anywhere at all. With type classes we can add conditions to type class instances. I.e. a Tuple is a Monoid, when both of its types are also Monoids. With inheritance you can't do this.
Let's say I come up with a combinator:
def optional[M[_]: Applicative, A, B](fn: Kleisli[M, A, B]) =
Kleisli[M, Option[A], Option[B]] {
case Some(t) => fn(t).map(_.some)
case None => Applicative[M].point(none[B])
}
This combinator maps any Kleisli[M, A, B] to Kleisli[M, Option[A], Option[B].
However, after some time, I realize (admittedly with the help of estewei on #scalaz) this can be made to work with containers more general than just Option, namely anything for which there is a Traverse instance:
def traverseKleisli[M[_]: Applicative, F[_]: Traverse, A, B](k: Kleisli[M, A, B]) =
Kleisli[M, F[A], F[B]](k.traverse)
so that optional can now be defined as:
def optional[M[_]: Applicative, A, B](fn: Kleisli[M, A, B]) =
traverseKleisli[M, Option, A, B](fn)
However, I'd like to verify that at least the resulting type signature is equal to the original definition of optional, and whereas I could resort to hovering over both definitions in my IDE (Ensime in my case) and compare the response, I'd like a more solid way of determining that.
I tried:
implicitly[optional1.type =:= optional2.type]
but (obviously?) that fails due to both identifies being considered unstable by scalac.
Other than perhaps temporarily making both of the functions objects with an apply method, are there any easy ways to compare their static types without resorting to relying on hints from IDE presentation compilers?
P.S. the name optional comes from the fact that I use that combinator as part of a validation DSL to take a Kleisli-wrapped Validation[String, T] and turn it into a Kleisli-wrapped Validation[String, Option[T]] that verifies the validity of optional values if present.
The problem you're having is that a method is not a value in scala, and values are monotyped. You can test that a particular "instance" of your method has the correct type (using a utility function from shapeless):
val optional1Fix = optional1[Future, Int, String] _
val optional2Fix = optional2[Future, Int, String] _
import shapeless.test._
sameTyped(optional1Fix)(optional2Fix)
but as with unit tests, this is somewhat unsatisfying as even if we test several instances we can't be sure it works for everything. (Note that implicitly[optional1Fix.type =:= optional2Fix.type] still doesn't work, I assume because the compiler never realizes when two path-dependent types are equal).
For a full solution we have to see the complete function as a value, so we would have to replace it with an object with an apply method as you suggest (analogous to shapeless' ~>). The only alternative I can think of is a macro, which would have to be applied to the object containing the methods, and know which methods you wanted to compare; writing a specific macro for this specific test seems a little excessive.
In a simple way, what are context and view bounds and what is the difference between them?
Some easy-to-follow examples would be great too!
I thought this was asked already, but, if so, the question isn't apparent in the "related" bar. So, here it is:
What is a View Bound?
A view bound was a mechanism introduced in Scala to enable the use of some type A as if it were some type B. The typical syntax is this:
def f[A <% B](a: A) = a.bMethod
In other words, A should have an implicit conversion to B available, so that one can call B methods on an object of type A. The most common usage of view bounds in the standard library (before Scala 2.8.0, anyway), is with Ordered, like this:
def f[A <% Ordered[A]](a: A, b: A) = if (a < b) a else b
Because one can convert A into an Ordered[A], and because Ordered[A] defines the method <(other: A): Boolean, I can use the expression a < b.
Please be aware that view bounds are deprecated, you should avoid them.
What is a Context Bound?
Context bounds were introduced in Scala 2.8.0, and are typically used with the so-called type class pattern, a pattern of code that emulates the functionality provided by Haskell type classes, though in a more verbose manner.
While a view bound can be used with simple types (for example, A <% String), a context bound requires a parameterized type, such as Ordered[A] above, but unlike String.
A context bound describes an implicit value, instead of view bound's implicit conversion. It is used to declare that for some type A, there is an implicit value of type B[A] available. The syntax goes like this:
def f[A : B](a: A) = g(a) // where g requires an implicit value of type B[A]
This is more confusing than the view bound because it is not immediately clear how to use it. The common example of usage in Scala is this:
def f[A : ClassManifest](n: Int) = new Array[A](n)
An Array initialization on a parameterized type requires a ClassManifest to be available, for arcane reasons related to type erasure and the non-erasure nature of arrays.
Another very common example in the library is a bit more complex:
def f[A : Ordering](a: A, b: A) = implicitly[Ordering[A]].compare(a, b)
Here, implicitly is used to retrive the implicit value we want, one of type Ordering[A], which class defines the method compare(a: A, b: A): Int.
We'll see another way of doing this below.
How are View Bounds and Context Bounds implemented?
It shouldn't be surprising that both view bounds and context bounds are implemented with implicit parameters, given their definition. Actually, the syntax I showed are syntactic sugars for what really happens. See below how they de-sugar:
def f[A <% B](a: A) = a.bMethod
def f[A](a: A)(implicit ev: A => B) = a.bMethod
def g[A : B](a: A) = h(a)
def g[A](a: A)(implicit ev: B[A]) = h(a)
So, naturally, one can write them in their full syntax, which is specially useful for context bounds:
def f[A](a: A, b: A)(implicit ord: Ordering[A]) = ord.compare(a, b)
What are View Bounds used for?
View bounds are used mostly to take advantage of the pimp my library pattern, through which one "adds" methods to an existing class, in situations where you want to return the original type somehow. If you do not need to return that type in any way, then you do not need a view bound.
The classic example of view bound usage is handling Ordered. Note that Int is not Ordered, for example, though there is an implicit conversion. The example previously given needs a view bound because it returns the non-converted type:
def f[A <% Ordered[A]](a: A, b: A): A = if (a < b) a else b
This example won't work without view bounds. However, if I were to return another type, then I don't need a view bound anymore:
def f[A](a: Ordered[A], b: A): Boolean = a < b
The conversion here (if needed) happens before I pass the parameter to f, so f doesn't need to know about it.
Besides Ordered, the most common usage from the library is handling String and Array, which are Java classes, like they were Scala collections. For example:
def f[CC <% Traversable[_]](a: CC, b: CC): CC = if (a.size < b.size) a else b
If one tried to do this without view bounds, the return type of a String would be a WrappedString (Scala 2.8), and similarly for Array.
The same thing happens even if the type is only used as a type parameter of the return type:
def f[A <% Ordered[A]](xs: A*): Seq[A] = xs.toSeq.sorted
What are Context Bounds used for?
Context bounds are mainly used in what has become known as typeclass pattern, as a reference to Haskell's type classes. Basically, this pattern implements an alternative to inheritance by making functionality available through a sort of implicit adapter pattern.
The classic example is Scala 2.8's Ordering, which replaced Ordered throughout Scala's library. The usage is:
def f[A : Ordering](a: A, b: A) = if (implicitly[Ordering[A]].lt(a, b)) a else b
Though you'll usually see that written like this:
def f[A](a: A, b: A)(implicit ord: Ordering[A]) = {
import ord.mkOrderingOps
if (a < b) a else b
}
Which take advantage of some implicit conversions inside Ordering that enable the traditional operator style. Another example in Scala 2.8 is the Numeric:
def f[A : Numeric](a: A, b: A) = implicitly[Numeric[A]].plus(a, b)
A more complex example is the new collection usage of CanBuildFrom, but there's already a very long answer about that, so I'll avoid it here. And, as mentioned before, there's the ClassManifest usage, which is required to initialize new arrays without concrete types.
The context bound with the typeclass pattern is much more likely to be used by your own classes, as they enable separation of concerns, whereas view bounds can be avoided in your own code by good design (it is used mostly to get around someone else's design).
Though it has been possible for a long time, the use of context bounds has really taken off in 2010, and is now found to some degree in most of Scala's most important libraries and frameworks. The most extreme example of its usage, though, is the Scalaz library, which brings a lot of the power of Haskell to Scala. I recommend reading up on typeclass patterns to get more acquainted with all the ways in which it can be used.
EDIT
Related questions of interest:
A discussion on types, origin and precedence of implicits
Chaining implicits
Following watching Nick Partidge's presentation on deriving scalaz, I got to looking at this example, which is just awesome:
import scalaz._
import Scalaz._
def even(x: Int) : Validation[NonEmptyList[String], Int]
= if (x % 2 ==0) x.success else "not even: %d".format(x).wrapNel.fail
println( even(3) <|*|> even(5) ) //prints: Failure(NonEmptyList(not even: 3, not even: 5))
I was trying to understand what the <|*|> method was doing, here is the source code:
def <|*|>[B](b: M[B])(implicit t: Functor[M], a: Apply[M]): M[(A, B)]
= <**>(b, (_: A, _: B))
OK, that is fairly confusing (!) - but it references the <**> method, which is declared thus:
def <**>[B, C](b: M[B], z: (A, B) => C)(implicit t: Functor[M], a: Apply[M]): M[C]
= a(t.fmap(value, z.curried), b)
So I have a few questions:
How come the method appears to take a higher-kinded type of one type parameter (M[B]) but can get passed a Validation (which has two type paremeters)?
The syntax (_: A, _: B) defines the function (A, B) => Pair[A,B] which the 2nd method expects: what is happening to the Tuple2/Pair in the failure case? There's no tuple in sight!
Type Constructors as Type Parameters
M is a type parameter to one of Scalaz's main pimps, MA, that represents the Type Constructor (aka Higher Kinded Type) of the pimped value. This type constructor is used to look up the appropriate instances of Functor and Apply, which are implicit requirements to the method <**>.
trait MA[M[_], A] {
val value: M[A]
def <**>[B, C](b: M[B], z: (A, B) => C)(implicit t: Functor[M], a: Apply[M]): M[C] = ...
}
What is a Type Constructor?
From the Scala Language Reference:
We distinguish between first-order
types and type constructors, which
take type parameters and yield types.
A subset of first-order types called
value types represents sets of
(first-class) values. Value types are
either concrete or abstract. Every
concrete value type can be represented
as a class type, i.e. a type
designator (§3.2.3) that refers to a
class1 (§5.3), or as a compound type
(§3.2.7) representing an intersection
of types, possibly with a refinement
(§3.2.7) that further constrains the
types of itsmembers. Abstract value
types are introduced by type
parameters (§4.4) and abstract type
bindings (§4.3). Parentheses in types
are used for grouping. We assume that
objects and packages also implicitly
define a class (of the same name as
the object or package, but
inaccessible to user programs).
Non-value types capture properties of
identifiers that are not values
(§3.3). For example, a type
constructor (§3.3.3) does not directly
specify the type of values. However,
when a type constructor is applied to
the correct type arguments, it yields
a first-order type, which may be a
value type. Non-value types are
expressed indirectly in Scala. E.g., a
method type is described by writing
down a method signature, which in
itself is not a real type, although it
gives rise to a corresponding function
type (§3.3.1). Type constructors are
another example, as one can write type
Swap[m[_, _], a,b] = m[b, a], but
there is no syntax to write the
corresponding anonymous type function
directly.
List is a type constructor. You can apply the type Int to get a Value Type, List[Int], which can classify a value. Other type constructors take more than one parameter.
The trait scalaz.MA requires that it's first type parameter must be a type constructor that takes a single type to return a value type, with the syntax trait MA[M[_], A] {}. The type parameter definition describes the shape of the type constructor, which is referred to as its Kind. List is said to have the kind '* -> *.
Partial Application of Types
But how can MA wrap a values of type Validation[X, Y]? The type Validation has a kind (* *) -> *, and could only be passed as a type argument to a type parameter declared like M[_, _].
This implicit conversion in object Scalaz converts a value of type Validation[X, Y] to a MA:
object Scalaz {
implicit def ValidationMA[A, E](v: Validation[E, A]): MA[PartialApply1Of2[Validation, E]#Apply, A] = ma[PartialApply1Of2[Validation, E]#Apply, A](v)
}
Which in turn uses a trick with a type alias in PartialApply1Of2 to partially apply the type constructor Validation, fixing the type of the errors, but leaving the type of the success unapplied.
PartialApply1Of2[Validation, E]#Apply would be better written as [X] => Validation[E, X]. I recently proposed to add such a syntax to Scala, it might happen in 2.9.
Think of this as a type level equivalent of this:
def validation[A, B](a: A, b: B) = ...
def partialApply1Of2[A, B C](f: (A, B) => C, a: A): (B => C) = (b: B) => f(a, b)
This lets you combine Validation[String, Int] with a Validation[String, Boolean], because the both share the type constructor [A] Validation[String, A].
Applicative Functors
<**> demands the the type constructor M must have associated instances of Apply and Functor. This constitutes an Applicative Functor, which, like a Monad, is a way to structure a computation through some effect. In this case the effect is that the sub-computations can fail (and when they do, we accumulate the failures).
The container Validation[NonEmptyList[String], A] can wrap a pure value of type A in this 'effect'. The <**> operator takes two effectful values, and a pure function, and combines them with the Applicative Functor instance for that container.
Here's how it works for the Option applicative functor. The 'effect' here is the possibility of failure.
val os: Option[String] = Some("a")
val oi: Option[Int] = Some(2)
val result1 = (os <**> oi) { (s: String, i: Int) => s * i }
assert(result1 == Some("aa"))
val result2 = (os <**> (None: Option[Int])) { (s: String, i: Int) => s * i }
assert(result2 == None)
In both cases, there is a pure function of type (String, Int) => String, being applied to effectful arguments. Notice that the result is wrapped in the same effect (or container, if you like), as the arguments.
You can use the same pattern across a multitude of containers that have an associated Applicative Functor. All Monads are automatically Applicative Functors, but there are even more, like ZipStream.
Option and [A]Validation[X, A] are both Monads, so you could also used Bind (aka flatMap):
val result3 = oi flatMap { i => os map { s => s * i } }
val result4 = for {i <- oi; s <- os} yield s * i
Tupling with `<|**|>`
<|**|> is really similar to <**>, but it provides the pure function for you to simply build a Tuple2 from the results. (_: A, _ B) is a shorthand for (a: A, b: B) => Tuple2(a, b)
And beyond
Here's our bundled examples for Applicative and Validation. I used a slightly different syntax to use the Applicative Functor, (fa ⊛ fb ⊛ fc ⊛ fd) {(a, b, c, d) => .... }
UPDATE: But what happens in the Failure Case?
what is happening to the Tuple2/Pair in the failure case?
If any of the sub-computations fails, the provided function is never run. It only is run if all sub-computations (in this case, the two arguments passed to <**>) are successful. If so, it combines these into a Success. Where is this logic? This defines the Apply instance for [A] Validation[X, A]. We require that the type X must have a Semigroup avaiable, which is the strategy for combining the individual errors, each of type X, into an aggregated error of the same type. If you choose String as your error type, the Semigroup[String] concatenates the strings; if you choose NonEmptyList[String], the error(s) from each step are concatenated into a longer NonEmptyList of errors. This concatenation happens below when two Failures are combined, using the ⊹ operator (which expands with implicits to, for example, Scalaz.IdentityTo(e1).⊹(e2)(Semigroup.NonEmptyListSemigroup(Semigroup.StringSemigroup)).
implicit def ValidationApply[X: Semigroup]: Apply[PartialApply1Of2[Validation, X]#Apply] = new Apply[PartialApply1Of2[Validation, X]#Apply] {
def apply[A, B](f: Validation[X, A => B], a: Validation[X, A]) = (f, a) match {
case (Success(f), Success(a)) => success(f(a))
case (Success(_), Failure(e)) => failure(e)
case (Failure(e), Success(_)) => failure(e)
case (Failure(e1), Failure(e2)) => failure(e1 ⊹ e2)
}
}
Monad or Applicative, how shall I choose?
Still reading? (Yes. Ed)
I've shown that sub-computations based on Option or [A] Validation[E, A] can be combined with either Apply or with Bind. When would you choose one over the other?
When you use Apply, the structure of the computation is fixed. All sub-computations will be executed; the results of one can't influence the the others. Only the 'pure' function has an overview of what happened. Monadic computations, on the other hand, allow the first sub-computation to influence the later ones.
If we used a Monadic validation structure, the first failure would short-circuit the entire validation, as there would be no Success value to feed into the subsequent validation. However, we are happy for the sub-validations to be independent, so we can combine them through the Applicative, and collect all the failures we encounter. The weakness of Applicative Functors has become a strength!