7
votes

Given the following implementations of f in Haskell and Scala:

Prelude> let f x y = x == y
Prelude> :t f
f :: Eq a => a -> a -> Bool

Scala:

scala> trait Equal[A] { def ===(x: A, y: A): Boolean }
defined trait Equal

scala> implicit val equalsInt = new Equal[Int] {
     |  def ===(x: Int, y: Int):Boolean = (x == y)
     | }
equalsInt: Equal[Int] = $anon$1@3daa422a

scala> def f[A : Equal](x: A, y: A): Boolean = 
     |   implicitly[Equal[A]].===(x, y)
f: [A](x: A, y: A)(implicit evidence$1: Equal[A])Boolean

scala> f(10, 20)
res0: Boolean = false

scala> f(55, 55)
res1: Boolean = true

Watching this video, Typeclasses v. the World, my incomplete understanding is that Scala's implicit resolution, i.e. how it achieves type-classes, is susceptible to incorrect/inconsistent resolution of implicits. But, Haskell does not use implicits for typeclasses, so there's no such problem in Haskell.

Considering the differences between Scala and Haskell's typeclass implementations, what are the possible problems of the above f definition in Scala that are absent from Haskell?

1

1 Answers

5
votes

One problem the Scala version can have that the Haskell version can't, is that in Scala you can define more than one instance of Equal[Int] in scope when the implicit resolution machinery is trying to find an instance. Which is when you can get an error like:

<console>:12: error: ambiguous implicit values:
 both value EqualInt1 of type => Equal[Int]
 and value EqualInt2 of type => Equal[Int]
 match expected type Equal[Int]
              f(1, 2)
               ^

Update. As Carl points out in a comment, another problem is that you can have different instances in scope at different points in the code, so that calling f could use these different instances with very different results and no compile-time or run-time errors.