I have a toy DSL
case class Logging[A](msg: String, action: A)
case class Persist[A](msg: String, action: A)
type Effect[A] = EitherK[Logging, Persist, A]
that I want to pair with an equally toy interpreter
case class CoLogging[A](run: String => A)
case class CoPersist[A](run: String => A)
type Interp[A] = Tuple2K[CoLogging, CoPersist, A]
Here is an program example:
def prog(implicit L: Logs[Effect], P: Persists[Effect]): Free[Effect, Unit] =
P.store("bar") >> L.log("foo")
and here is the interpreter:
def interpretEffect(implicit CL: CoLogs[IO], CP: CoPersists[IO]): Cofree[Interp, IO[Unit]] =
Cofree.unfold(IO.pure(())) { a: IO[Unit] => Tuple2K(CoLogging(CL.coLog(a)), CoPersist(CP.coPersist(a))) }
I've paid due diligence and defined functors as well as injection implicits. The compiler complains that it cannot find an instance cats.Functor[[A]cats.data.Tuple2K[example.CoLogging,example.CoPersist,A]], even though I am importing cats.data.Tuple2K._ where the instance is implicitly defined.
I can't see what I'm doing wrong, it must be something stupid. Do you have any idea? All the code can be seen in this gist.
The compiler complains that it cannot find an instance
cats.Functor[[A]cats.data.Tuple2K[example.CoLogging,example.CoPersist,A]],
even though I am importing cats.data.Tuple2K._ where the instance is implicitly defined.
Functor[Tuple2K[F, G, ?]] is defined via Tuple2KInstances8#catsDataFunctorForTuple2K if Functor[F] and Functor[G] were defined. The thing is that Functor[CoLogging] and Functor[CoPersist] weren't.
Add
object CoLogging {
implicit val coLoggingFunctor: Functor[CoLogging] = new Functor[CoLogging] {
override def map[A, B](fa: CoLogging[A])(f: A => B): CoLogging[B] = CoLogging(fa.run andThen f)
}
}
and
object CoPersist {
implicit val coPersistFunctor: Functor[CoPersist] = new Functor[CoPersist] {
override def map[A, B](fa: CoPersist[A])(f: A => B): CoPersist[B] = CoPersist(fa.run andThen f)
}
}
and everything should compile.
The thing is the order of implicits. Move object functors to the beginning and everything should compile.
For using cats functors in your code, you need to try to add settings in your build.sbt file.
scalacOptions += "-Ypartial-unification"
Maybe ths will hepls you. This is limitation of scala compiler https://issues.scala-lang.org/browse/SI-2712
Related
In this session SystemFw gives an example of implementing State[S, A] wih vanilla scala, When follow the exmple, I run into a trouble in supplying a Applicative definition for the vanilla State type (In order to get the commands.traverse work. See code here
I tried to make a implicit def to solve the Applicative instance, but didn't figure out how to deal with the 2 type parameter.
How to implement Applicative for this type:
case class State[S, A](modify: S => (A, S)) {
def runA(initial: S): A = modify(initial)._1
def flatMap[B](f: A => State[S, B]): State[S, B] =
State { s =>
val (result, nextState) = modify(s)
f(result).modify(nextState)
}
}
Wrong code:
implicit def stateApplicative[S, A]: Applicative[State[S, A]] = new Applicative[State[S, A]] {
override def pure[A](x: A): State[A???] = ??? // error
override def ap[A, B](ff: State[A => B])(fa: State[A???]): State[B] = ??? // error
}
Basically, the solution to this problem is always fixing one type parameter.
In the case of a State you want the value inside the state to change but no the type of the state itself so you fix S.
So you can create an application for a given particular state, for example Int
type IntState[A] = State[A, Int]
implicit final val intStateApplicative: Applicative[IntState] =
new Applicative[IntState] {
// Some implementation.
}
However, after you fill the implementation you will see that the fact of knowing that S was Int was meaningless. And that we could just copy and paste the whole code if S would have been String or whatever.
So, what we want is a way to say that this works for any S, we can do that with a type lambda (i.e. a function in the type level).
type StateTypeFun[S] = { type F[A] = State[A, S] }
implicit final def stateApplicative[S]: Applicative[StateTypeFun[S]#F] =
new Applicative[StateTypeFun[S]#F] {
// Some implementation.
}
And that is how we solve this problem.
Note that the type alias is unnecessary but makes the code easier to read, but you could have done Applicative[({ type F[A] = State[A, S]})#F].
BTW, because this necessity of creating type lambdas is somewhat common in Scala 2 we have kind projector, and Scala 3 has proper syntax support for it.
In Haskell I got:
data Foo a where
Bar :: a -> Foo a
Map :: (a -> b) -> Foo a -> Foo b
instance Functor Foo where
fmap = Map
In Scala I came up with:
import cats.Functor
trait Foo[A]
case class Bar[A](t: A) extends Foo[A]
case class Map[A,B](fun: A => B,foo: Foo[A]) extends Foo[B]
implicit val fooFunctor: Functor[Foo] = new Functor[Foo] {
def map[A,B](fa: Foo[A])(f: A => B) = Map(f,fa)
}
But Bar(40).map(_+2) gives me:
error: value map is not a member of Bar[Int]
I fairly new to Scala and don't know the way of inheritance that well.
What am I missing?
You need to upcast Bar(40) to Foo explicitly, and import the syntax implicits:
import cats.syntax.functor._
(Bar(40): Foo[Int]).map(_+2)
You need the upcast because Scala will infer the type Bar[Int] for the expression Bar(40) and this then interferes with finding the appropriate implicit that adds the map method. For this reason you sometimes see helper methods in the companion object to do the upcast for you:
object Foo {
def bar[A](a: A): Foo[A] = Bar(a)
// etc.
}
I thought a little bit about how one could solve this problem. Basically, we want to provide the functor operations even if only a super type is a functor. It seems to be impossible to express, that some higher-kinded type is the super type of an other, e.g. something like this is not possible: def bla[F[_], R[_] <: F]
We can however provide a conversion from R[] to F[] implicitly together with the functor for B:
abstract class ProvidesFor[R,F[_],FF[_[_]],A](val value: FF[F]) {
def convert(r: R): F[A]
}
implicit def providesFunctorForBar[A] =
new ProvidesFor[Bar[A],Foo,Functor,A](Functor[Foo]) {
override def convert(r: Bar[A]): Foo[A] = r
}
So the implict val will provide us with a functor for Foo and a convertion from Bar to Foo.
Now we can provide an implicit converstion to Functor.Ops like this:
implicit class FunctorOps[R[_],F[_],A](target: R[A])(implicit tc: ProvidesFor[R[A],F,Functor,A])
extends Functor.Ops[F,A] {
override val self = tc.convert(target)
override val typeClassInstance = tc.value
override def map[B](f: A => B): F[B] = typeClassInstance.map(self)(f)
override def imap[B](f: A => B)(g: B => A): F[B] = map(f)
}
Now this works as expected:
Bar(1).imap(_+2)(_+5)
We can also do the same for Map:
implicit def providesFunctorForMap[A,B] =
new ProvidesFor[Map[A,B],Foo,Functor,B](Functor[Foo]) {
override def convert(r: Map[A,B]): Foo[B] = r
}
Map((_:Int) + 1,Bar(5)).map(_+2)
For some strange reason I had to implement map and imap when extending Functor.Ops even though these methods are not abstract. In fact it compiles fine when I do not implement them but it fails at runtime with an AbstractMethodError. So somehow the compiler thinks the implementations are there but they are not. I suspect they are using some kind of byte code optimization tool that removes those implementations.
Apparently unapply/unapplySeq in extractor objects do not support implicit parameters. Assuming here an interesting parameter a, and a disturbingly ubiquitous parameter b that would be nice to hide away, when extracting c.
[EDIT]: It appears something was broken in my intellij/scala-plugin installation that caused this. I cannot explain. I was having numerous strange problems with my intellij lately. After reinstalling, I can no longer reprodce my problem. Confirmed that unapply/unapplySeq do allow for implicit parameters! Thanks for your help.
This does not work (**EDIT:yes, it does):**
trait A; trait C; trait B { def getC(a: A): C }
def unapply(a:A)(implicit b:B):Option[C] = Option(b.getC(a))
In my understanding of what an ideal extractor should be like, in which the intention is intuitively clear also to Java folks, this limitation basically forbids extractor objects which depend on additional parameter(s).
How do you typically handle this limitation?
So far I've got those four possible solutions:
1) The simplest solution that I want to improve on: don't hide b, provide parameter b along with a, as normal parameter of unapply in form of a tuple:
object A1{
def unapply(a:(A,B)):Option[C] = Option(a._2.getC(a._1)) }
in client code:
val c1 = (a,b) match { case A1(c) => c1 }
I don't like it because there is more noise deviating that deconstruction of a into c is important here. Also since java folks, that have to be convinced to actually use this scala code, are confronted with one additional synthactic novelty (the tuple braces). They might get anti-scala aggressions "What's all this? ... Why then not use a normal method in the first place and check with if?".
2) define extractors within a class encapsulating the dependence on a particular B, import extractors of that instance. At import site a bit unusual for java folks, but at pattern match site b is hidden nicely and it is intuitively evident what happens. My favorite. Some disadvantage I missed?
class BDependent(b:B){
object A2{
def unapply(a:A):Option[C] = Option(b.getC(a))
} }
usage in client code:
val bDeps = new BDependent(someB)
import bDeps.A2
val a:A = ...
val c2 = a match { case A2(c) => c }
}
3) declare extractor objects in scope of client code. b is hidden, since it can use a "b" in local scope. Hampers code reuse, heavily pollutes client code (additionally, it has to be stated before code using it).
4) have unapply return Option of function B => C. This allows import and usage of an ubitious-parameter-dependent extractor, without providing b directly to the extractor, but instead to the result when used. Java folks maybe confused by usage of function values, b not hidden:
object A4{
def unapply[A,C](a:A):Option[B => C] = Option((_:B).getC(a))
}
then in client code:
val b:B = ...
val soonAC: B => C = a match { case A4(x) => x }
val d = soonAC(b).getD ...
Further remarks:
As suggested in this answer, "view bounds" may help to get extractors work with implicit conversions, but this doesn't help with implicit parameters. For some reason I prefer not to workaround with implicit conversions.
looked into "context bounds", but they seem to have the same limitation, don't they?
In what sense does your first line of code not work? There's certainly no arbitrary prohibition on implicit parameter lists for extractor methods.
Consider the following setup (I'm using plain old classes instead of case classes to show that there's no extra magic happening here):
class A(val i: Int)
class C(val x: String)
class B(pre: String) { def getC(a: A) = new C(pre + a.i.toString) }
Now we define an implicit B value and create an extractor object with your unapply method:
implicit val b = new B("prefix: ")
object D {
def unapply(a: A)(implicit b: B): Option[C] = Option(b getC a)
}
Which we can use like this:
scala> val D(c) = new A(42)
c: C = C#52394fb3
scala> c.x
res0: String = prefix: 42
Exactly as we'd expect. I don't see why you need a workaround here.
The problem you have is that implicit parameters are compile time (static) constraints, whereas pattern matching is a runtime (dynamic) approach.
trait A; trait C; trait B { def getC(a: A): C }
object Extractor {
def unapply(a: A)(implicit b: B): Option[C] = Some(b.getC(a))
}
// compiles (implicit is statically provided)
def withImplicit(a: A)(implicit b: B) : Option[C] = a match {
case Extractor(c) => Some(c)
case _ => None
}
// does not compile
def withoutImplicit(a: A) : Option[C] = a match {
case Extractor(c) => Some(c)
case _ => None
}
So this is a conceptual problem, and the solution depends on what you actually want to achieve. If you want something along the lines of an optional implicit, you might use the following:
sealed trait FallbackNone {
implicit object None extends Optional[Nothing] {
def toOption = scala.None
}
}
object Optional extends FallbackNone {
implicit def some[A](implicit a: A) = Some(a)
final case class Some[A](a: A) extends Optional[A] {
def toOption = scala.Some(a)
}
}
sealed trait Optional[+A] { def toOption: Option[A]}
Then where you had implicit b: B you will have implicit b: Optional[B]:
object Extractor {
def unapply(a:A)(implicit b: Optional[B]):Option[C] =
b.toOption.map(_.getC(a))
}
def test(a: A)(implicit b: Optional[B]) : Option[C] = a match {
case Extractor(c) => Some(c)
case _ => None
}
And the following both compile:
test(new A {}) // None
{
implicit object BImpl extends B { def getC(a: A) = new C {} }
test(new A {}) // Some(...)
}
an example use case:
def div2(i: Int): Validation[String, Int] =
if (i%2 == 0) Validation.success(i/2)
else Validation.failure("odd")
def div4(i: Int) = for {
a <- div2(i)
b <- div2(a)
} yield b
error: Unable to unapply type scalaz.Validation[String,Int] into a type constructor of kind M[_] that is classified by the type class scalaz.Bind
I guess the error is caused by the compiler can't find a Monad instance for Validation[String, Int]
I can make one for myself, like:
object Instances {
implicit def validationMonad[E] = new Monad[({type L[A] = Validation[E, A]})#L] {
override def point[A](a: => A) =
Validation.success(a)
override def bind[A, B](fa: Validation[E, A])(f: A => Validation[E, B]) =
fa bind f
}
}
but why doesn't Validation have it already? after all, Validation already has the bind method defined.
moreover, I can't have import Validation._ and import Instances._ together anymore (this took me looong to figure out...), because of another complicated error...
ambiguous implicit values: something like both validationMonad (my instance), and method ValidationInstances1 in trait ValidationInstances2... both match some Functor of Validation...
should I modify the source of scalaz? or I'm completely missing something~?
please help~
I'm using scalaz 7.0.0-M2
As discussed in the Scalaz group, the problem seems to be that ap would accumulate errors whereas (pseudo-)monadic composition would only operate on the value part of Validation.
Therefore, one cannot be expressed in terms of the other and thus no monad instance exists for Validation.
The issue is that the applicative functor as implied by the monad does not equal the actual applicative functor
Hi I read the interesting post from Debasish about the implicitly function. I have wrote this code:
def find[C <: Business](id: String) = {
collection.findOneByID(id).map(x=> implicitly[DBObject => C].apply(x))
}
but it fails to compile with this compiler message:
could not find implicit value for parameter e: (com.mongodb.casbah.commons.Imports.DBObject) => C
what is my fault? anyone can help me?
UPDATE
My idea was this:
find is declared in a trait don't know nothing about DBObject, I don't want to put this dependency.
trait BusinessRepository {
def find[C <: Business](id: String): Option[C]
}
class MongoBusinessRepository {
val collection = ..
def find[C <: Business](id: String): Option[C] = {
collection.findOneByID(id).map(x=> implicitly[DBObject => C].apply(x))
}
implicit def DBObject2Hotel(x: DBObject): Hotel = {
// ...
// returning Hotel
}
}
case class Hotel(...) extends Business(...)
implicitly is just a convenience method to look up an implicit value that you know already exists. So it fails to compile when there is no such implicit value in scope.
A possible use case is when you use shortcut syntax for context bounds:
def find[C: Numeric](a: C, b: C): C = implicitly[Numeric[C]].plus(a, b)
Of course, in this example, the explicit form is less verbose
def find[C](a: C, b: C)(implicit n: Numeric[C]): C = n.plus(a, b)
You will find more thorough explanations in this Stackoverflow thread.
What I imagine you had in mind with your method is rather
def find[C <: Business](id: String)(implicit fun: DBObject => C) =
collection.findOneByID(id).map(fun)
I think that the problem comes from the fact that Scala compiler try to find an implicit definition of a function DBObject => C and that the only implicit definition that he can find is DBObject => Hotel that could be a solution but it's not strict. With your solution, the compiler is not able to know what should be C.
Maybe you should consider defining a DBObject2Business and so implicitly define a DBObject => Business function, or change your design to define C in a concrete class.