Generic Type "A" Not Found - scala

Going through the first exercise of FP in Scala's Monoid chapter, a compile-time error occurred when trying to create a new implementation of a trait in with "listMonoid."
object MonoidTesting1 {
trait Monoid[A] {
def op(a1: A, a2: A): A
def zero: A
}
val listMonoid = new Monoid[List[A]] {
def op(a1: List[A], a2: List[A]) = a1 ++ a2
val zero = Nil
}
}
C:\Users\Kevin\Workspace\side-work\Monoid>scalac MonoidTesting.scala
MonoidTesting.scala:12: error: not found: type A
val listMonoid = new Monoid[List[A]] {
^
MonoidTesting.scala:13: error: not found: type A
def op(a1: List[A], a2: List[A]) = a1 ++ a2
^
MonoidTesting.scala:13: error: not found: type A
def op(a1: List[A], a2: List[A]) = a1 ++ a2
^
three errors found
How can I create listMonoid in order to use an unspecified, generic type?

List is what actually called a free monoid. You need explicitly create A in scope of list Monoid:
object MonoidTest {
trait Monoid[A] {
def op(a1: A, a2: A): A
def zero: A
}
def listMonoid[A] = new Monoid[List[A]] {
def op(a1: List[A], a2: List[A]) = a1 ++ a2
val zero = List.empty[A]
}
}

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.

how to call filter on both Seq an Vector

I'd like to make a method that take a vector or a seq of of some type, let's say Int, and calls filter on it.
For example:
implicit class SharedOps[F](xs: F)(implicit ev: OneOf[F, Seq[Int] ::: Vector[Int] ::: HSNil]) {
def filter(x: Int):F = xs.filter({a:Int => a == x})
}
OneOf basically checks that F is either a Seq[Int] or a Vector[Int]
The tricky part is that I want the filter to return the same type as the input (e.g. Seq[Int] or Vector[Int]) but compiler is complaining
error: type mismatch;
found : scala.this.Function1[scala.this.Int,scala.this.Boolean]
required: scala.this.Int
def filter(x: Int):F = xs.filter({a:Int => a == x})
Somehow compiler forgot I started with a collection of sorts and thinks xs is a single thing.
So I changed the design:
implicit class SharedOps2[A,F[A]<:TraversableLike[A,A]](xs: F[A])(implicit ev: OneOf[F[A], Seq[Int] ::: Vector[Int] ::: HSNil]) {
def filter(x: A): F[A] = xs.filter({ a: Int => a == x })
}
Now compiler is complaining that: Expression of type A doesn't conform to expected type F[A]
Not sure how to take it from here. I'd like to avoid shapeless coproducts at this point.
For completeness here's the OneOf code:
sealed trait HSubset // HList
#implicitNotFound("No member of type class HSubset in scope for ${H}")
trait :::[+H, +T <: HSubset] extends HSubset // HCons ::
sealed trait HSNil extends HSubset // HNil
#implicitNotFound("No member of type class BelongsTo in scope for ${T}")
trait BelongsTo[T, U <: HSubset]
object BelongsTo {
implicit def baseCase[H, U <: HSubset]: BelongsTo[H, H ::: U] = null
implicit def recursiveCase[H, U <: HSubset, T](implicit ev: T BelongsTo U): T BelongsTo (H ::: U) = null
}
#implicitNotFound("No member of type class SubsetOf in scope for ${U} ${T}")
trait SubsetOf[U <: HSubset, T <: HSubset]
object SubsetOf {
implicit def baseCase[U1, U <: HSubset](implicit s: U1 BelongsTo U): SubsetOf[U1 ::: HSNil, U] = null
implicit def recursiveCase[U <: HSubset, T1, T <: HSubset](implicit ev1: T1 BelongsTo U, ev2: T SubsetOf U): (T1 ::: T) SubsetOf U = null
}
trait OneOf[T, U <: HSubset]
object OneOf {
implicit def baseCase[U <: HSubset, T](implicit s: T BelongsTo U): T OneOf U = null
implicit def recursiveCase[T, Ev <: HSubset, Target <: HSubset](implicit ev1: T OneOf Ev, ev2: Ev SubsetOf Target): T OneOf Target = null
}
This is the proposed typeclas.
My advice would be to use specific types like List & Vector instead of Seq.
trait Filter[F[_]] {
def filter[A](fa: F[A])(p: A => Boolean): F[A]
}
object Filter {
implicit final val VectorFilter: Filter[Vector] =
new Filter[Vector] {
override final def filter[A](vector: Vector[A])(p: A => Boolean): Vector[A] =
vector.filter(p)
}
implicit final val SeqFilter: Filter[Seq] =
new Filter[Seq] {
override final def filter[A](seq: Seq[A])(p: A => Boolean): Seq[A] =
seq.filter(p)
}
}
object syntax {
object filter {
implicit class FilterOps[F[_], A](private val fa: F[A]) extends AnyVal {
#inline
final def filter(p: A => Boolean)(implicit ev: Filter[F]): F[A] =
ev.filter(fa)(p)
}
}
}
import syntax.filter._
def foo[F[_] : Filter](xs: F[Int]): F[Int] =
xs.filter(i => (i % 2) == 0)
Which you can use like:
foo(Vector(1, 2, 3))
// res: Vector[Int] = Vector(2)
foo(List(1, 2, 3))
// could not find implicit value for evidence parameter of type ammonite.$sess.cmd0.Filter[List]
foo(Seq(1, 2, 3))
// res: Seq[Int] = List(2)
BTW, it is worth mentioning that such typeclass already exists in cats
TraversableLike.filter returns Repr, which is type passed as second type parameter to TraversableLike. You need F[A] there instead of A. This compiles for me:
implicit class SharedOps2[A,F[A]<:TraversableLike[A,F[A]]](xs: F[A])(implicit ev: OneOf[F[A], Seq[A] ::: Vector[A] ::: HSNil]) {
def filter(x: A): F[A] = xs.filter({ a: A => a == x })
}
Note also type of a changed to A, because this is the type inside F[A] collection.
fiddle

Scala: use def or val when instantiating from a trait?

I'm reading Functional Programming in Scala by Chiusano and Bjarnason.
In Chapter 10, they define the Monoid trait:
trait Monoid[A] {
def op(a1: A, a2: A): A
def zero: A
}
Two example instances of the trait are the following:
1) String Monoid:
val stringMonoid = new Monoid[String] {
def op(a1: String, a2: String) = a1 + a2
val zero = ""
}
2) List Monoid:
def listMonoid[A] = new Monoid[List[A]] {
def op(a1: List[A], a2: List[A]) = a1 ++ a2
val zero = Nil
}
My question is, why do we use val in the case of stringMonoid, and def in listMonoid?
stringMonoid is a string type new Monoid[String]
listMonoid is a generic type new Monoid[List[A]]. To pass this generic type A it is declared as def
def listMonoid[A] = new Monoid[List[A]]
Edit
To address the comment:
If you still want is to use val for listMonoid, then define what list is going to have in it.
val listMonoid = new Monoid[List[Int]] {
def op(a1: List[Int], a2: List[Int]) = a1 ++ a2
def zero = List.empty
}

Implement the realization of function in scala

I have a function
def foo[A](a1: A, a2: A): A = a1|+|a2
It need to implement the realization
The result must be:
foo[Test](Test(1), Test(2)) // Test(3)
I wrote some code in IDEA worksheet, but it is not compile
case class Test(num: Int)
object Test {
implicit val test = new Writer[Test] {
def write(v1: Test, v2: Test) = {
Test(v1.num + v2.num)
}
}
}
trait Writer[A] {
def write(v1: A, v2: A): A
}
implicit class someT[A](a1: A) {
def |+|(a2: A)(implicit writer: Writer[A]) = {
writer.write(a1, a2)
}
}
def foo[A](a1: A, a2: A): A = a1|+|a2
foo[Test](Test(1), Test(2))
the output error is:
Error:(32, 34) could not find implicit value for parameter writer: A$A213.this.Writer[A]
def foo[A](a1: A, a2: A): A = a1|+|a2
^
Error:(32, 34) not enough arguments for method |+|: (implicit writer: A$A213.this.Writer[A])A.
Unspecified value parameter writer.
def foo[A](a1: A, a2: A): A = a1|+|a2
^
You're missing the implicit Writer[A] required on foo:
def foo[A](a1: A, a2: A)(implicit writer: Writer[A])
Or if you prefer context bounds:
def foo[A : Writer](a1: A, a2: A)
Now, the compiler can in turn see that |+| has a Writer[A] in scope.

Scala Monoid Combinator for Options

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.