TypeClasses in ScalaZ - scala

I'm reading ScalaZ tutorial and now I'm on the section of Yes-No type class. Eventual goal is to get 1.truthy to return true. Here is the implementation of the typeclass:
trait CanTruthy[A] { self =>
/** #return true, if `a` is truthy. */
def truthys(a: A): Boolean
}
object CanTruthy {
def apply[A](implicit ev: CanTruthy[A]): CanTruthy[A] = ev
def truthys[A](f: A => Boolean): CanTruthy[A] = new CanTruthy[A] {
def truthys(a: A): Boolean = f(a)
}
}
trait CanTruthyOps[A] {
def self: A
implicit def F: CanTruthy[A]
final def truthy: Boolean = F.truthys(self)
}
object ToCanIsTruthyOps {
implicit def toCanIsTruthyOps[A](v: A)(implicit ev: CanTruthy[A]) =
new CanTruthyOps[A] {
def self = v
implicit def F: CanTruthy[A] = ev
}
}
implicit val intCanTruthy: CanTruthy[Int] = CanTruthy.truthys({
case 0 => false
case _ => true
})
Looks a little scary to me. We introduced 2 new traits to achieve that. But we can achieve the same just by using implicit classes:
trait CanTruthy {
def truthy: Boolean
}
object CanTruthy{
implicit class CanTruthyInt(i: Int) extends CanTruthy{
override def truthy: Boolean = i match {
case 0 => false
case _ => true
}
}
}
Looks the same to me. So why do we need to use the way in the tutorial? What kind of things I missed? Can you explain what is the difference?

I think the problem here is a misreading of the scope of this sentence:
Eventual goal is to get 1.truthy to return true.
This is what we're trying to do with the CanTruthyOps stuff, but it's not the goal of the CanTruthy type class, and more generally syntactic concerns like this aren't the goal of type classes.
The goal of type classes is to allow us to constrain types in a simple, flexible, compositional way. The type parameter-less CanTruthy approach doesn't really support the simple part or the flexible part or the compositional part very nicely (arguably the implementation of type classes in Scala isn't very simple either, but it's at least a little simpler and definitely more flexible and compositional).
Take this method from the tutorial, for example (lightly modified to avoid the Any):
// Type class style
def truthyIf[A: CanTruthy, B](cond: A)(ifyes: => B)(ifno: => B): B =
if (cond.truthy) ifyes else ifno
If you wanted to translate this into your type parameter-less style, at first things seem pretty good:
// Parameterless style
def truthyIf[B](cond: CanTruthy)(ifyes: => B)(ifno: => B): B =
if (cond.truthy) ifyes else ifno
But now suppose that you needed to keep the original type around. There are lots of reasons this might be necessary—you might want to sort a collection of values with scala.Ordering before you check the truthiness of one of them, for example, or you might have a variation of this method where the original type is also the return type (in the type class style here):
// Type class style
def truthyOrElse[A: CanTruthy](cond: A)(ifno: => A): A =
if (cond.truthy) cond else ifno
Now the translation is less fun:
// Type parameter-less style
def truthyOrElse[A <% CanTruthy](cond: A)(ifno: => A): A =
if (cond.truthy) ifyes else ifno
Where the funky <% thing is syntactic sugar for an implicit parameter:
// Type parameter-less style (desugared)
def truthyOrElse[A](cond: A)(ifno: => A)(implicit evidence$1: A => CanTruthy): A =
if (cond.truthy) cond else ifno
But the : in the type class style is also syntactic sugar:
// Type class style, desugared
def truthyOrElse[A](cond: A)(ifno: => A)(implicit evidence$2: CanTruthy[A]): A =
if (cond.truthy) cond else ifno
Note that these methods look almost identical—in both you're writing a method that requires some implicit evidence (at compilation time) that A is truthy. In the type parameter-less style this evidence is an implicit conversion, while in the type class style it's an implicit value of a generic type.
There are several advantages to the latter approach. One kind of abstract one is that it allows us to separate the "here's some evidence that I know how to do X for this type" concern from the purely syntactic "I can call .x on this thing" concern. Sure, this separation requires some extra machinery (two traits instead of one), but keeping a clean line between the syntactic and semantic issues is arguably worth it.
Another (related) advantage is that the type class can be more efficient, since it allows us to forgo the syntax, and therefore also the extra allocation it involves:
// Type class style, no syntax
def truthyOrElse[A](cond: A)(ifno: => A)(implicit ev: CanTruthy[A]): A =
if (ev.truthys(cond)) cond else ifno
Another advantage comes up in cases where the operation you're trying to provide evidence about involves more than one value:
trait Addable[A] {
def plus(a: A, b: A): A
}
object Addable {
implicit val intAddable: Addable[Int] = new Addable[Int] {
def plus(a: Int, b: Int): Int = a + b
}
}
There's just no nice way to do this kind of thing as an Int => Addable implicit conversion.
The type class approach similarly handles cases where you have multiple types that you need your operation to work on, etc., while the type parameter-less approach doesn't really (at least not in any reasonably clean way).
So to sum up: if you just want some nice enrichment methods that you're generally using in situations where you have concrete types, the type parameter-less approach is totally reasonable and may involve a little less code. If you want to be able to abstract over types that support some operation in an efficient, flexible, generic, and reasonably elegant way, write a type class.

Related

How to reference parameter of a higher kinded type parameteter?

Suppose you have a trait like this:
trait Foo[A]{
def foo: A
}
I want to create a function like this:
def getFoo[A <: Foo[_]](a: A) = a.foo
The Scala Compiler deduces Any for the return type of this function.
How can I reference the anonymous parameter _ in the signature (or body) of getFoo?
In other words, how can I un-anonymize the parameter?
I want to be able to use the function like
object ConcreteFoo extends Foo[String] {
override def foo: String = "hello"
}
val x : String = getFoo(ConcreteFoo)
which fails compilation for obvious reasons, because getFoo is implicitly declared as Any.
If this is not possible with Scala (2.12 for that matter), I'd be interested in the rational or the technical reason for this limitation.
I am sure there are articles and existing questions about this, but I appear to be lacking the correct search terms.
Update: The existing answer accurately answers my question as stated, but I suppose I wasn't accurate enough regarding my actual usecase. Sorry for the confusion. I want to be able to write
def getFoo[A <: Foo[_]] = (a: A) => a.foo
val f = getFoo[ConcreteFoo.type]
//In some other, unrelated place
val x = f(ConcreteFoo)
Because I don't have a parameter of type A, the compiler can't deduce the parameters R and A if I do
def getFoo[R, A <: Foo[R]]: (A => R) = (a: A) => a.foo
like suggested. I would like to avoid manually having to supply the type parameter R (String in this case), because it feels redundant.
To answer literally your exact question:
def getFoo[R, A <: Foo[R]](a: A): R = a.foo
But since you don't make any use of the type A, you can actually omit it and the <: Foo[..] bound completely, retaining only the return type:
def getFoo[R](a: Foo[R]): R = a.foo
Update (the question has been changed quite significantly)
You could smuggle in an additional apply invocation that infers the return type from a separate implicit return type witness:
trait Foo[A] { def foo: A }
/** This is the thing that remembers the actual return type of `foo`
* for a given `A <: Foo[R]`.
*/
trait RetWitness[A, R] extends (A => R)
/** This is just syntactic sugar to hide an additional `apply[R]()`
* invocation that infers the actual return type `R`, so you don't
* have to type it in manually.
*/
class RetWitnessConstructor[A] {
def apply[R]()(implicit w: RetWitness[A, R]): A => R = w
}
def getFoo[A <: Foo[_]] = new RetWitnessConstructor[A]
Now it looks almost like what you wanted, but you have to provide the implicit, and you have to call getFoo[ConcreteFoo.type]() with additional pair of round parens:
object ConcreteFoo extends Foo[String] {
override def foo: String = "hey"
}
implicit val cfrw = new RetWitness[ConcreteFoo.type, String] {
def apply(c: ConcreteFoo.type): String = c.foo
}
val f = getFoo[ConcreteFoo.type]()
val x: String = f(ConcreteFoo)
I'm not sure whether it's really worth it, it's not necessarily the most straightforward thing to do. Type-level computations with implicits, hidden behind somewhat subtle syntactic sugar: that might be too much magic hidden behind those two parens (). Unless you expect that the return type of foo will change very often, it might be easier to just add a second generic argument to getFoo, and write out the return type explicitly.

Make a class extend a generic trait in Scala

I thought this should work to make a light alternative to type classes but it does not :
trait Summable[T] {
def sumWith(other: T): T
}
implicit class StringSummable(s: String) extends Summable[String]{
def sumWith(other: String): String = s + other
}
def sumAll[T <: Summable[T]](list: List[T]): T = {
list.reduceLeft((sum, element) => sum.sumWith(element))
}
sumAll(List("1","2","3"))
I have this error : inferred type arguments [lang.this.String] do not conform to method sumAll's type parameter bounds [T <: Summable[T]]
Is there a trick to make this work?
Thanks
Yes, there is a "trick", it's literally a single-character change:
':' -> '%'
from subtyping to "implicit convertibility" bounds:
trait Summable[T] {
def sumWith(other: T): T
}
implicit class StringSummable(s: String) extends Summable[String]{
def sumWith(other: String): String = s + other
}
def sumAll[T <% Summable[T]](list: List[T]): T = {
list.reduceLeft((sum, element) => sum.sumWith(element))
}
sumAll(List("1","2","3"))
Note that this tends to fall apart rather quickly. For example, as soon as you need a zero-ary function that returns an empty String, you are essentially out of luck with this approach, whereas it is trivial with a typeclass (as Monoid[T] shows). Without it, you can't even define sumAll properly, because it doesn't work on empty lists.
Note that the historical development so far has been away from implicit conversions, and towards the typeclasses, not the other way round.

What's wrong with delegation-based typeclasses encoding

Typeclasses coherence is a well-known problem.
For example a Monad has to be a Functor and a Traversable has to be a Functor as well. If has to be is represented via inheritance (Monad[F[_]] extends Functor[F[_]]) then there will most probably be ambiguity in implicit resolution.
I applied the rule of thumb: if you have a problem with inheritance replace it by delegation. Here is an example:
trait Semigroup[A] {
def append(a: A, b: A): A
}
trait Monoid[A] {
def zero(): A
val semigroup: Semigroup[A]
def append(a: A, b: A): A = semigroup.append(a, b)
}
implicit object IntSemigroup extends Semigroup[Int] {
override def append(a: Int, b: Int): Int = a + b
}
implicit object IntMonoid extends Monoid[Int] {
override def zero(): Int = 0
override val semigroup: Semigroup[Int] = IntSemigroup
}
def main(args: Array[String]): Unit = {
println(implicitly[Monoid[Int]].append(2, 3))
}
I guess this approach doesn't work since it's obvious but not used in scalaz/cats. Could you please point me to the problems?
With representing it using inheritance, you get inference for free - a Monad is automatically a Functor. With representing it using delegation, you don't.
You would have to define lots of implicit conversions to get around that, which would be a pain. But (simple) implicit conversions don't chain automatically in Scala, so with them, it still wouldn't infer Functor from Monad via the intermediate type class Applicative.
P.S. In practice, you usually don't get ambiguity in resolution if you do things right. That means, (a) use foo.some instead of Some(foo) and the like, and (b) use value classes or similar to semantically disambiguate types for which you wish to use different instances. And if all else fails, explicitly pass in the instance (which you can't do in Haskell).

Implicit class vs Implicit conversion to trait

I'm trying to add new functions to existing types (so I can have the IDE auto suggest relevant functions for types I don't have control over, eg Future[Option[A]]). I've explored both implicit classes and implicit conversions to accomplish this and they both seem to offer the same behavior.
Is there any effective difference between using an implicit class:
case class Foo(a: Int)
implicit class EnrichedFoo(foo: Foo) {
def beep = "boop"
}
Foo(1).beep // "boop"
And using an implicit conversion:
case class Foo(a: Int)
trait Enriched {
def beep: String
}
implicit def fooToEnriched(foo: Foo) = new Enriched {
def beep = "boop"
}
Foo(1).beep // "boop"
I suppose one difference here might be that the first example creates a one-off class instead of a trait, but I could easily adapt the implicit class to extend an abstract trait, eg:
case class Foo(a: Int)
trait Enriched {
def beep: String
}
implicit class EnrichedFoo(foo: Foo) extends Enriched {
def beep = "boop"
}
Foo(1).beep // "boop"
As far as I'd know, they're pretty much exactly the same. The scoping rules also equally apply to both.
In my opinion, I'd use the implicit classes for your kind of situation. They were probably created exactly for something like that.
Implicit conversions, to me, are more appropriate when you already actually have two different kind of classes and want to convert between the two.
You can check out the initial proposal for implicit classes right here.
There it says:
A new language construct is proposed to simplify the creation of classes which provide extension methods to another type.
You can even see how it desugars implicit classes. The following:
implicit class RichInt(n: Int) extends Ordered[Int] {
def min(m: Int): Int = if (n <= m) n else m
...
}
will desugar into:
class RichInt(n: Int) extends Ordered[Int] {
def min(m: Int): Int = if (n <= m) n else m
...
}
implicit final def RichInt(n: Int): RichInt = new RichInt(n)
Well to me its a matter of preference. Actually the implicit classes came into being to ease the creation of classes which provide extension methods to another type.
Implicit classes add a lot of value to value classes though.
To add on Luka Jacobowitz answer: Implicit classes are basically extensions. Implicit conversion is used to tell the compiler that it may be treated as something with extension.
Sounds nearly the same. Two things of interest from implicit conversion to have some difference:
First: You may need to activate the language feature for disabling warnings when using implicit conversion.
Second: The term of "converting" the type may be confusing:
Implicit conversions are applied in two situations:
If an expression e is of type S, and S does not conform to the expression’s expected type T.
[Or:] In a selection e.m with e of type S, if the selector m does not denote a member of S.
case class Foo(a: Int)
trait Enriched {
def beep: String
}
implicit def fooToEnriched(foo: Foo) = new Enriched {
def beep = "boop"
}
Foo(1) match {
case _:Enriched => println("is an Enriched")
case _:Foo => println("no, was a Foo")
}
// no, was a Foo
but it may be treated as an Enriched...
val enriched: Enriched = Foo(2)
enriched match {
case _:Enriched => println("is an Enriched")
case _:Foo => println("no, was a Foo")
}
// is an Enriched
// plus unreachable code warning: case _:Foo => println("no, was a Foo")

Provide type-class when implementing/override method

I would prefer to work more with type-classes but having some issues:
Given the following interface
trait Processor[A] {
def process[B](f: A => B): Processor[B]
}
I have an implementation that needs an Ordering[A] for some other reasons. Hence the method process needs an Ordering[B] to construct a Processor[B].The following is what I would like to do, but it does obviously not work:
class Plant[A, OA <: Ordering[A]] extends Processor[A] {
def process[B:Ordering](f: A => B): Processor[B] = null // Plant[B, OB <: Ordering[B]]
}
How can I provide the Ordering[B] for the implementation of process?
I know the reason for this is, that Ordering[A] is passed as an implicit second argument. I don't know but shouldn't there be special support for type-classes in Scala similar to Haskell to recognize what I want (only allow Bs that have an Ordering) in the implementation above without this "workaround"?
No, and this shouldn't work at all. Given your defnition of Processor, this code will compile:
val processor: Processor[Int] = foo() // foo() is some function that returns a Processor
processor.process[Object](x => new Object())
Now if foo is actually implemented as
def foo() = new Plant[Int]()
then its process method won't work with B = Object.
I'm not sure I fully understand what you're trying to achieve, but perhaps you could make Processor generic on the context bound?
trait Processor[A, Bound[_]] {
def process[B: Bound](f: A => B): Processor[B, Any]
}
class Plant[A: Ordering] extends Processor[A, Ordering] {
def process[B: Ordering](f: A => B) = ???
}