Scala Monoid Combinator for Options - scala

Let's say that I have a Monoid trait as below:
trait Monoid[A] {
def combine(a1: A, a2: A): A
def identity: A
}
Now if I want to write an optionMonoid for this, I could write it like this:
val optionMonoid1 = new Monoid[Option[A]] {
def combine(a1: Option[A], a2: Option[A2]) a1 orElse a2
def identity = None
}
This given the fact that I do not know anything about the inner type in the Option. But what if I want to have the combine operator in such a way that I want to really combine the inner types in the Option?

One option:
trait Semigroup[A] {
def combine(a1: A, a2: A): A
}
trait Monoid[A] extends Semigroup[A] {
def identity: A
}
def optionMonoid2[A](implicit sgA: Semigroup[A]) = new Monoid[Option[A]] {
def combine(a1: Option[A], a2: Option[A2]) = (a1, a2) match {
case (Some(b1), Some(b2)) => Some(sgA.combine(b1, b2))
case _ => a1.orElse(a2)
}
def identity = None
}
It's easy to verify monoid laws hold.

Related

Dealing with implicit typeclass conflict

I'm trying to deal with an ambiguous implicits problem, and (relatedly) figure out what best practise should be for parameterizing typeclasses. I have a situation where I am using a typeclass to implement a polymorphic method. I initially tried the approach below:
abstract class IsValidTypeForContainer[A]
object IsValidTypeForContainer {
implicit val IntIsValid = new IsValidTypeForContainer[Int] {}
implicit val DoubleIsValid = new IsValidTypeForContainer[Double] {}
}
abstract class IsContainer[A, B: IsValidTypeForContainer] {
def getElement(self: A, i: Int): B
def get[R](self: A, ref: R)(implicit gets: GetsFromContainerMax[A, R, B]): gets.Out = gets.get(self, ref)
def fromList(self: A, other: List[B]): A = ???
}
implicit class IsContainerOps[A, B: IsValidTypeForContainer](self: A)(implicit
isCont: IsContainer[A, B],
) {
def getElement(i: Int) = isCont.getElement(self, i)
def get[R](ref: R)(implicit gets: GetsFromContainerMax[A, R, B]): gets.Out = isCont.get(self, ref)
def fromList(other: List[B]): A = isCont.fromList(self, other)
}
abstract class GetsFromContainerMax[A, R, B: IsValidTypeForContainer] {
type Out
def get(self: A, ref: R): Out
}
object GetsFromContainerMax {
type Aux[A, R, B, O] = GetsFromContainerMax[A, R, B] { type Out = O }
def instance[A, R, B: IsValidTypeForContainer, O](func: (A, R) => O): Aux[A, R, B, O] = new GetsFromContainerMax[A, R, B] {
type Out = O
def get(self: A, ref: R): Out = func(self, ref)
}
implicit def getsForListInt[A, B: IsValidTypeForContainer](implicit
isCons: IsContainer[A, B],
): Aux[A, List[Int], B, A] = instance(
(self: A, ref: List[Int]) => {
val lst = ref.map(isCons.getElement(self, _)).toList
isCons.fromList(self, lst)
}
)
}
Where I have given the GetsContainerMax typeclass three parameters - one for the IsContainer object, one for the reference and one for the data type of the IsContainer object.
When I then try to use this, I get a compile error:
case class List1[B: IsValidTypeForContainer] (
data: List[B]
)
implicit def list1IsContainer[B: IsValidTypeForContainer] = new IsContainer[List1[B], B] {
def getElement(self: List1[B], i: Int): B = self.data(i)
def fromList(self: List1[B], other: List[B]): List1[B] = ???
}
val l1 = List1[Int](List(1,2,3))
implicitly[IsContainer[List1[Int], Int]].get(l1, List(1,2)) // Works
implicitly[List1[Int] => IsContainerOps[List1[Int], Int]] // Works
l1.get(List(1,2)) // Does not work
If I use the -Xlog-implicits build parameter, it tells me that
ambiguous implicit values: both value IntIsValid in object IsValidTypeForContainer of type example.Test.IsValidTypeForContainer[Int] and value DoubleIsValid in object IsValidTypeForContainer of type example.Test.IsValidTypeForContainer[Double] match expected type example.Test.IsValidTypeForContainer[B]
Which seems to make sense; presumably I am bringing both of these implicits into scope by parameterizing the typeclass with the generic B.
My next thought was therefore to try to reduce the number of generic parameters for IsValidTypeForContainer to the minimum, in order to have only one typeclass in scope per type of R, likeso:
abstract class GetsFromContainerMin[R] {
type Out
def get[A](self: A, ref: R)(implicit isCont: IsContainer[A, _]): Out
}
object GetsFromContainerMin {
type Aux[R, O] = GetsFromContainerMin[R] { type Out = O }
def instance[A, R, O](func: (A, R) => O): Aux[R, O] = new GetsFromContainerMin[R] {
type Out = O
def get(self: A, ref: R)(implicit isCont: IsContainer[A, _]): Out = func(self, ref)
}
implicit def getsForListInt[A](implicit isCons: IsContainer[A, _]): Aux[List[Int], A] = instance(
(self: A, ref: List[Int]) => {
val lst = ref.map(isCons.getElement(self, _)).toList
isCons.fromList(self, lst) // type mismatch - found: List[Any], required: List[_$3]
}
)
}
But this seems to not only not solve the problem, but to generate an additional error in that the compiler can no longer type-check that type B implements IsValidTypeForContainer.
Any help gratefully received.
So I've messed around with this a bit and seem to have found the solution. The typeclass-with-three-parameters approach works, if I use
implicit class IsContainerOps[A, B](self: A)(implicit
isCont: IsContainer[A, B],
)
instead of
implicit class IsContainerOps[A, B: IsValidTypeForContainer](self: A)(implicit
isCont: IsContainer[A, B],
)
I am not exactly sure why this is and if anyone would care to respond I'd be interested to know. Are multiple typeclasses created if you use a context bound like in the original example, one for each implementation of IsValidTypeForContainer?
Regarding GetsFromContainerMin, only type classes without polymorphic methods can have constructor method instance (in companion object) because of the lack of polymorphic functions in Scala 2. In Scala 3 you'll be able to write
def instance[R, O](func: [A] => (A, R) => O): Aux[R, O] = ...
So far you have to write
object GetsFromContainerMin {
type Aux[R, O] = GetsFromContainerMin[R] { type Out = O }
implicit def getsForListInt[A](implicit isCons: IsContainer[A, _]): Aux[List[Int], A] = new GetsFromContainerMin[List[Int]] {
override type Out = A
override def get[A1](self: A1, ref: List[Int])(implicit isCont: IsContainer[A1, _]): Out = {
val lst = ref.map(isCons.getElement(self, _)).toList
// ^^^^
isCons.fromList(self, lst)
// ^^^^
}
}
}
I guess compile errors are pretty clear
type mismatch;
found : self.type (with underlying type A1)
required: A
Regarding your first question,
implicit class IsContainerOps[A, B: IsValidTypeForContainer](self: A)(implicit
isCont: IsContainer[A, B]
)
is desugared to
implicit class IsContainerOps[A, B](self: A)(implicit
ev: IsValidTypeForContainer[B],
isCont: IsContainer[A, B]
)
but order of implicits is significant. If you modify IsContainerOps to
implicit class IsContainerOps[A, B](self: A)(implicit
isCont: IsContainer[A, B],
ev: IsValidTypeForContainer[B],
)
then l1.get(List(1,2)) will compile.
Implicits are resolved from left to right. You want firstly A to be inferred (from self), then IsContainer[A, B] to be resolved, so B to be inferred and IsValidTypeForContainer[B] to be resolved and not vice versa firstly A to be inferred, then IsValidTypeForContainer[B] to be resolved, and at this step B is not restricted, there is no connection between A and B, so possibly B can be not inferred or inferred to be Nothing, so IsContainer[A, B] is not resolved. I'm a little simplifying (not every time when you swap implicits you break resolution) but general strategy of implicit resolution and type inference is as I described.

Writing a single implicit class for both a value and a functor of that value

I often find myself having to perform what is pretty much the same operation on both a value and also a functor of that value. I usually achieve this with two implicit classes, like this:
implicit class Apimped(a: A) {
def doSomething: B = ???
}
implicit class FApimped[F[_]: Functor](fa: F[A]) {
def doSomething: F[B] = Functor[F].map(fa)(a => a.doSomething)
}
So then I can do this, for example:
a.doSomething //B
Option(a).doSomething //Option[B]
However, it seems a bit unwieldy having to write two implicit classes (often for each value type) to do this. My question is, is there anyway to achieve the above with only a single implicit class? That is, the map operation would be implicit in cases when you call doSomething on a functor of the value. Thanks.
I don't know whether it's in Scalaz/Cats (maybe, cannot guarantee that it's not there), but in principle, it does work. Here is a little demo without any dependencies that demonstrates the principle.
Assume you have these typeclasses from either Scalaz or Cats:
import scala.language.higherKinds
trait Functor[F[_]] {
def map[A, B](a: F[A])(f: A => B): F[B]
}
type Id[X] = X
implicit object IdFunctor extends Functor[Id] {
def map[A, B](a: A)(f: A => B): B = f(a)
}
implicit object OptionFunctor extends Functor[Option] {
def map[A, B](a: Option[A])(f: A => B) = a map f
}
you can then either write or find in the library a typeclass that works like the following contraption:
trait EverythingIsAlwaysAFunctor[A, B, F[_]] {
def apply(a: A): F[B]
def functor: Functor[F]
}
object EverythingIsAlwaysAFunctor {
implicit def functorIsFunctor[A, F[_]](implicit f: Functor[F])
: EverythingIsAlwaysAFunctor[F[A], A, F] = {
new EverythingIsAlwaysAFunctor[F[A], A, F] {
def apply(fa: F[A]): F[A] = fa
def functor: Functor[F] = f
}
}
implicit def idIsAlsoAFunctor[A]
: EverythingIsAlwaysAFunctor[A, A, Id] = {
new EverythingIsAlwaysAFunctor[A, A, Id] {
def apply(a: A): Id[A] = a
def functor: Functor[Id] = implicitly[Functor[Id]]
}
}
}
This thing does the following:
If the value A is already of shape F[B] for some functor F, then uses this functor
In all other cases, it pretends that A is actually Id[A]
Now you can write your DoSomething-pimp-my-library-syntax thing with a single doSomething method:
implicit class DoSomething[A, F[_]](a: A)(
implicit eiaaf: EverythingIsAlwaysAFunctor[A, Int, F]
) {
def doSomething: F[String] = eiaaf.functor.map(eiaaf(a))("*" * _)
}
and then it just works in all cases:
val x = Option(42).doSomething
val y = 42.doSomething
println(x)
println(y)
prints:
Some(******************************************)
******************************************

Shapeless: Iterate over the types in a Coproduct

I want to do something really simple, but I'm struggling to craft the correct search or just understanding some of the solutions I've seen.
Given a method that takes a generic type parameter which is a Coproduct;
def apply[T <: Coproduct] = {
...
}
How can I iterate over the types that form the coproduct? Specifically, for each type that is a case class, I'd like to recursively examine each field and build up a map with all the information.
Currently I'm working around this using a builder pattern, which I'll post here in case it's useful to others;
class ThingMaker[Entities <: Coproduct] private {
def doThings(item: Entities): Set[Fact] = {
...
}
def register[A <: Product with Serializable]: ThingMaker[A :+: Entities] = {
// useful work can be done here on a per type basis
new ThingMaker[A :+: Entities]
}
}
object ThingMaker {
def register[A <: Product with Serializable]: ThingMaker[A :+: CNil] = {
// useful work can be done here on a per type basis
new ThingMaker[A :+: CNil]
}
}
If you just want to inspect values, you can simply pattern match on a coproduct like on any other value...
def apply[T <: Coproduct](co: T): Any = co match {
case Inl(MyCaseClass(a, b, c)) => ???
...
}
...but if you want to be more precise than that, for instance to have a return type that depends on the input, or to inspect the types inside this coproduct to summon implicits, then you can write the exact same pattern matching expression using a type class and several implicit definition:
trait MyFunction[T <: Coproduct] {
type Out
def apply(co: T): Out
}
object MyFunction {
// case Inl(MyCaseClass(a, b, c)) =>
implicit val case1 = new MyFunction[Inl[MyCaseClass]] {
type Out = Nothing
def apply(co: Inl[MyCaseClass]): Out = ???
}
// ...
}
In general, when you want iterate over all types of a coproduct, you will always follow the same tail recursive structure. As a function:
def iterate[T <: Coproduct](co: T): Any = co match {
case Inr(head: Any) => println(v)
case Inl(tail: Coproduct) => iterate(tail)
case CNil => ???
}
Or as a "dependently typed function":
trait Iterate[T <: Coproduct]
object Iterate {
implicit def caseCNil = new Iterate[CNil] {...}
implicit def caseCCons[H, T <: Coproduct](implicit rec: Iterate[T]) =
new Iterate[H :+: T] {...}
}
You can for instance ontain the name of each type in a coproduct using an addition ClassTag implicit:
trait Iterate[T <: Coproduct] { def types: List[String] }
object Iterate {
implicit def caseCNil = new Iterate[CNil] {
def types: List[String] = Nil
}
implicit def caseCCons[H, T <: Coproduct]
(implicit
rec: Iterate[T],
ct: reflect.ClassTag[H]
) =
new Iterate[H :+: T] {
def types: List[String] = ct.runtimeClass.getName :: rec.types
}
}
implicitly[Iterate[Int :+: String :+: CNil]].types // List(int, java.lang.String)
Because of the way Scala lets you influence implicit priority, it's actually possible to translate any recursive function with pattern matching into this "dependently typed function" pattern. This is unlike Haskell where such function can only be written if call cases of the match expression are provably non-overlapping.

Is there a typeclass for all sequences in Scala?

I'm messing around with algebraic structures, and I find the Numeric typeclass very handy for well, representing numeric values.
So I can write my monoid instance this way:
implicit def add[A: Numeric] = new Monoid[A] {
def mempty = implicitly[Numeric[A]].zero
def mappend(a0: A, a1: A) = implicitly[Numeric[A]].plus(a0, a1)
}
This looks like a dandy. But what can I do with sequences? I can't find a typeclass that does standard Scala collection sequences. I would like to write something like this:
def concat[A : SeqTC] = new Monoid[A] {
def mempty = implicitly[SeqTC[A]].empty
def mappend(a0: A, a1: A) = implicitly[SeqTC[A]].++(a0, a1)
}
According to #TrustNoOne's comment, this is what I achieved to do. And it works great.
def concat[A, S[A] <: Seq[A]](implicit bf: CanBuildFrom[S[A], A, S[A]]) = new Monoid[S[A]] {
def mempty = bf().result()
def mappend(a0: S[A], a1: S[A]) = bf.apply().++=(a0).++=(a1).result()
}

Conversion from Function to sets of custom types

I have a set of classes that looks something like this, which are (annoyingly) not in a single inheritance hierarchy:
trait Mxy[A,B] { def apply(a: A): B }
trait Mzz[ C ] { def apply(c: C): C }
trait Mix[ B] { def apply(i: Int): B }
trait Mxi[A ] { def apply(a: A): Int }
trait Mii { def apply(i: Int): Int }
The challenge is to map Function1 into these classes using converters (so you call .m to switch over); direct implicit conversion makes it too hard to figure out what the code is really doing.
As long as the most specific M is always okay, it's doable. You can write implicit conversions that look something like
abstract class MxyMaker[A, B] { def m: Mxy[A, B] }
abstract class MiiMaker { def m: Mii }
trait Priority2 {
implicit def f2mxy[A, B](f: Function1[A, B]) =
new MxyMaker[A, B] { def m = new Mxy[A, B] { def apply(a: A) = f(a) } }
}
// Bunch of missing priorities here in the full case
object Convert extends Priority2 {
implicit def f2mii[A](f: Function1[A, Int])(implicit evA: Int =:= A) =
new MiiMaker { def m = new Mii{
def apply(i: Int) = (f.asInstanceOf[Function1[Int,Int]]).apply(i)
} }
}
Now whenever you have an Int => Int you get a Mii, and for anything else you get a Mxy. (If you don't ask for evA then ((a: Any) => 5).m comes up as a Mii because of the contravariance of Function1 in its input argument parameter.)
So far so good. But what if you are in a context where you need not a Mii but a Mxy?
def muse[A, B](m: Mxy[A,B]) = ???
Now inferring the most specific type isn't what you want. But, alas,
scala> muse( ((i: Int) => 5).m )
<console>:18: error: type mismatch;
found : Mii
required: Mxy[?,?]
muse( ((i: Int) => 5).m )
^
Now what? If Mxy were a superclass of Mii it would be fine, but it's not and I can't change it. I could parameterize m with an output type and have a set of typeclass-like things that do the correct conversion depending on output type and then ask the user to type .m[Mxy] manually. But I want to skip the manual part and somehow pick up the type context from the call to muse without messing up things like val mippy = ((i: Int) = 5).m.
The astute may be able to think of a case like this in the wild, but it's easier to work with this "minimization" to get the principles right.