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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With