I'm learning category theory.
I understand the concept of reader monad, it's even pretty easy to implement:
case class Reader[DEP, A](g: DEP => A) {
def apply(dep: DEP): A = g(dep)
def map[B](f: A => B): Reader[DEP, B] = Reader(dep => f(apply(dep)))
def flatMap[B](f: A => Reader[DEP, B]): Reader[DEP, B] = Reader(dep => f(apply(dep)) apply dep)
}
However, I have problems implementing it with constraint to some generic Monad interface, i.e
trait Monad[A] {
def pure(a: A): Monad[A]
def map[B](f: A => B): Monad[B]
def flatMap[B](f: A => Monad[B]): Monad[B]
}
let's forgot for a second that there's an applicative or functor and let's just put these 3 methods here.
Now, having this interface I have problems implementing ReaderMonad.
map method is pretty straighforward, but what about pure and flatMap?
What does it even mean to have pure on Reader?
To implement flatMap, I need to have a function from A to Reader[DEP, B], but I have A => Monad[B], thus I'm not possible to access apply.
case class Reader[DEP, A](g: DEP => A) extends Monad[A] {
def apply(dep: DEP): A = g(dep)
override def pure(a: A): Reader[DEP, A] = Reader(_ => a) // what does it even mean in case of Reader
override def map[B](f: (A) => B): Reader[DEP, B] = Reader(dep => f(apply(dep)))
override def flatMap[B](f: (A) => Monad[B]): Reader[DEP, B] = ??? // to implement it, I need f to be (A) => Reader[DEP, B], not (A) => Monad[B]
}
Is it possible to implement it this way in scala? I tried to play around with self bound types, but it didn't work either.
I know libraries like scalaz or cats uses typeclasses to implement these types, but this is just for educational purpose.
As you've discovered when trying to implement flatMap, the problem with declaring the Monad trait as you have is you lose the particular monad type you're defining when chaining operations. The usual way of defining the Monad trait is to parameterise it by the type constructor the monad instance is being defined for e.g.
trait Monad[M[_]] {
def pure[A](a: A): M[A]
def map[A, B](f: A => B, m: M[A]): M[B]
def flatMap[A, B](f: A => M[B], m : M[A]): M[B]
}
So M is a unary type constructor such as List or Option. You can think of a Reader[DEP, A] as being a computation which depends on some environment type DEP which returns a value of type A. Since this has two type parameters you need to fix the environment parameter type when defining the monad instance:
case class Reader[DEP, A](g: DEP => A)
class ReaderMonad[DEP]() extends Monad[({type t[X] = Reader[DEP, X]})#t] {
def pure[A](a: A) = Reader[DEP, A](_ => a)
def map[A, B](f: A => B,m: Reader[DEP,A]): Reader[DEP,B] = Reader(env => f(m.g(env)))
def flatMap[A, B](f: A => Reader[DEP,B],m: Reader[DEP,A]): Reader[DEP,B] = Reader(env => f(m.g(env)).g(env))
}
({type t[X] = Reader[DEP, X]})#t is a type lambda used to partially apply one of the two parameters for Reader[DEP, A].
Now pure returns a Reader which ignores the environment and returns the given value directly.
flatMap constructs a Reader which when run will run the inner computation, use the result to construct the next computation and run it with the same environment.
Related
I want to map case class Bonus[A: Numeric](amt: A) over a Functor and it fails. The compilation error is
Error:(157, 69) could not find implicit value for evidence parameter of type Numeric[B] (No implicit Ordering defined for B.)
override def fmap[A, B](fa: Bonus[A])(f: A => B): Bonus[B] = Bonus(f(fa.amt))
In general, I want to fix the parameter type in Bonus to numbers. How do I do fix that? Thanks
The code snippet,
trait Functor[F[_]] {
def fmap[A, B](fa: F[A])(f: A => B): F[B]
}
def fmap[A, B, F[_]](fa: F[A])(f: A => B)(implicit ev: Functor[F]): F[B] = ev.fmap(fa)(f)
case class Bonus[A: Numeric](amt: A)
implicit val bonusFunctor = new Functor[Bonus] {
override def fmap[A, B](fa: Bonus[A])(f: A => B): Bonus[B] = Bonus(f(fa.amt)) // error
}
fmap(Bonus(123))(_ * 2)
Update 1
Thank you Mario & Dmytro for your answers.
Dmytro, your answer is precisely as what I found at https://users.scala-lang.org/t/how-to-add-type-constraint-to-functors-map-function/2055. It makes sense that either I drop the constraint or I use a constraint Functor. I accepted Mario's answer because it shows me an alternative solution because it is not possible with Functor.
Instance of Functor type class can be defined not for any type constructor.
The fact that type constructor F[_] has instance of type class Functor means that for any A, B, having a function A => B, you know how to transform F[A] to F[B].
But how to transform Bonus[A] to Bonus[B] for any A, B?
Types Bonus[A], Bonus[B] make sense for any A, B, even if they are not Numeric, but creating new instance of Bonus[B] via constructor makes sense only for B: Numeric.
Either remove context bound Numeric in case class Bonus[A: Numeric](amt: A) or Bonus is not a Functor.
If you define your own type class
trait NumericFunctor[F[_]] {
def fmap[A: Numeric, B: Numeric](fa: F[A])(f: A => B): F[B]
}
it will be not the standard functor over category of types but a custom functor over category of Numeric types.
Try
trait GFunctor[F[_], G[_]] {
def fmap[A, B](fa: F[A])(f: A => B)(implicit ga: G[A], gb: G[B]) : F[B]
}
def fmap[A, B, F[_], G[_]](fa: F[A])(f: A => B)(implicit ev: GFunctor[F, G], ga: G[A], gb: G[B]): F[B] = ev.fmap(fa)(f)
case class Bonus[A: Numeric](amt: A)
implicit val bonusFunctor = new GFunctor[Bonus, Numeric] {
override def fmap[A, B](fa: Bonus[A])(f: A => B)(implicit numA: Numeric[A], numbB: Numeric[B]): Bonus[B] = Bonus(f(fa.amt))
}
fmap(Bonus(123))(_ * 2)
which outputs
res0: Bonus[Int] = Bonus(246)
Note how we have made our typeclass solution aware of further bounds on A and B via
(implicit ga: G[A], gb: G[B])
How do you define an HKT in Scala to provide methods, such as map, as methods on instances instead of functions on objects?
I know you can
trait M[F[_]] {
def map[A, B](f: F[A])(fn: A => B): F[B]
}
object Q extends M[Q] {
def map[A, B](f: Q[A])(fn: A => B) = new Q(fn(f.e))
}
class Q[A](val e: A)
Q.map(new Q(1))(_.toDouble)
However, I want to use map on instances instead. I haven't seen any literature that does this, so I've written the following.
trait M[A, F[A]] {
def map[B](f: A => B): F[B]
}
class Q[A](val e: A) extends M[A, Q] {
def map[B](f: A => B) = new Q(f(e))
}
new Q(1).map(_.toDouble)
Is it idiomatic Scala? Does it do what map should do? Are there limitations compared with the object version above? (An aside, with extends M[A, Q[A]] it won't compile - why?)
I have seen
trait M[A] {
def map[B](f: A => B): M[B]
}
but then Q's map could return a class R[A] extends M[A] which isn't desired.
There's a library specifically for this: https://github.com/mpilquist/simulacrum
You can also do it yourself. The typical pattern is to define a corresponding implicit MOps class or whatever:
trait M[F[_]] {
def map[A, B](f: F[A])(fn: A => B): F[B]
}
implicit class MOps[F[_] : M, A](x: F[A]) {
def map[B](f: A => B): F[B] = implicitly[M[F]].map(x)(f)
}
Then example usage:
case class Box[A](a: A)
implicit val BoxM = new M[Box] {
def map[A, B](f: Box[A])(fn: A => B): Box[B] = Box(fn(f.a))
}
Box(2).map(_.toString)
But it's a lot of boilerplate, so simulacrum does it all for you (and more).
In scala, I have a container type with an error case and held type:
case class Extract[E, A](runView: View => EitherT[Future, E, (A, View)]) {...}
Which I intend to use as a sort of asynchronous state monad. I have implemented all of the map, flatMap utility methods for this.
I now want to mark this type as being a member of the Monad type class in scalaz, and I'm struggling to work out the syntax for specifying that the type parameter I want the type monadic over is the A type, since Monad takes a type with a single type parameter. Below is an incorrect attempt I made.
implicit def extractInterface[E] = new Monad[Extract[E, A]] {
def point[A](a: => A): Extract[E, A] = {...}
def bind[A, B](fa: Extract[E, A])(f: (A) => Extract[E, B]): Extract[E, B] = fa.flatMap(f)
}
I have tried looking at the scalaz instances for E \/ A, but they use a ? type parameter, for which I cannot find a definition.
Is there a syntactic trick to do what I want?
You should use type lambda
implicit def extractInterface[E] = new Monad[({ type λ[A] = Extract[E, A] })#λ] {
...
}
Alternatively you can use kind-projector plugin.
implicit def extractInterface[E] = new Monad[Extract[E, ?]] {
...
}
What is the ? type?
the code in question
trait Functor[F[_]] {
def map[A, B](f: A => B): F[A] => F[B]
}
sealed abstract class Free[F[_], A]
case class Return[F[_], A](x: A) extends Free[F, A]
case class Suspend[F[_], A](x: F[Free[F, A]]) extends Free[F, A]
case class Bind[F[_], A, B](x: () => Free[F, A], f: A => Free[F, B]) extends Free[F, B]
// this is the problem child
def liftF[F[_], A](x: => F[A])(implicit F: Functor[F]) =
Suspend[F, A](F.map { Return[F, A] }(x))
Now for some reason in the eclipse scala ide I'm getting a error with liftF
this error
- type mismatch; found : F[core01.Free.Return[F,A]] required: F[core01.Free[F,A]] Note: core01.Free.Return[F,A] <: core01.Free[F,A], but type
F is invariant in type _. You may wish to define _ as +_ instead. (SLS 4.5)
Now in the scalaz source there's no variance annotation, so what's the deal here? why the need for the variance annotation? is there are really need or is there a way around it?
I think you just have the functor arguments backwards on F.map. Give this a try:
def liftF[F[_], A](x: => F[A])(implicit F: Functor[F]) =
Suspend[F, A](F.map(x) { Return[F, A] } )
println(liftF(List(1, 2)))
"Suspend(List(Return(1), Return(2)))"
Note that either way you apply the elements to functor map you'll get the same result (you're version and the scalaz version):
def mapReverse[F[_], A, B](implicit F: Functor[F]) = {
(f:A => B) => (fa:F[A]) => F.map(fa)(f)
}
val reverse = mapReverse(F)({
Return[F, A]
})(x)
val normal = F.map(x)({
Return[F, A]
})
In this case reverse and normal are both F[Return[F, A]]. The way you apply the parameters is only helpful in the context of Suspend:
Suspend[F, A](F.map(x)({ Return[F, A] })) // works great
Suspend[F, A](normal) // fails to compile
Suspend[F, A](reverse) // fails to compile
I'm sure if you dig through the scala language spec long enough you can find out why the type inference works this way. If I had to guess, when fa is applied to F.map you get a function that's of type (A => B) => F[B]. So the compiler probably looks and sees that Suspend takes a Free so it makes this (A => Free[F, A]) => F[Free[F, A]] which will gladly take Return[F, A].apply as an argument. When you apply the arguments the other way you're strongly typed to Return instead of inferring a function Free.
I am struggling to understand the following function definition in Traverse trait in Scalaz:
def traverse[F[_] : Applicative, A, B](f: A => F[B], t: T[A]): F[T[B]]
The part I don't understand is F[_] : Applicative.
Now, let's see what Applicative is:
trait Applicative[Z[_]] extends Pointed[Z] with Apply[Z] {
override def fmap[A, B](fa: Z[A], f: A => B): Z[B] = this(pure(f), fa)
override def apply[A, B](f: Z[A => B], a: Z[A]): Z[B] = liftA2(f, a, (_:A => B)(_: A))
def liftA2[A, B, C](a: Z[A], b: Z[B], f: (A, B) => C): Z[C] = apply(fmap(a, f.curried), b)
}
Here, for traverse to work for some type F, one needs to bring an implicit object of type Applicative[F] in scope.
I'd like to understand several things:
Wat exactly does F[_] : Applicative mean?
Why does F[_] has something to do with Applicative? We need Applicative[F], not F[something] extends Applicative right?
Why does this method use implicit values of type Applicative[F] without declaring implicit parameters?
I think all three questions can be answered with the fact that this notation:
def traverse[F[_] : Applicative, A, B](f: A => F[B], t: T[A]): F[T[B]]
is equivalent to this:
def traverse[F[_], A, B](f: A => F[B], t: T[A])(implicit $ev: Applicative[F]): F[T[B]]
The first notation is known as a context bound for F[_].