I'm reading some articles about ScalaZ and have a question about understanding it. In this article, we generalize the sum function, to abstract away the type to be summed.
def sum[T](xs: List[T])(implicit m: Monoid[T]) = //...
Where
trait Monoid[A] is defined as follows:
trait Monoid[A] {
def mappend(a1: A, a2: A): A
def mzero: A
}
Yes, this is pretty clear. Monoid here corresponds to the algebraic monoid structure. Now in this article it abstracts over lists. To do this we define the following trait:
trait FoldLeft[F[_]] {
def foldLeft[A, B](xs: F[A], b: B, f: (B, A) => B): B
}
object FoldLeft {
implicit val FoldLeftList: FoldLeft[List] = new FoldLeft[List] {
def foldLeft[A, B](xs: List[A], b: B, f: (B, A) => B) = xs.foldLeft(b)(f)
}
}
So now we can define the sum function as follows:
def sum[M[_]: FoldLeft, A: Monoid](xs: M[A]): A = {
val m = implicitly[Monoid[A]]
val fl = implicitly[FoldLeft[M]]
fl.foldLeft(xs, m.mzero, m.mappend)
}
I'm not a theory category expert, but it looks like Applicative functor to me. Is that correct? Can we provide such similarity to category theory.
Applicative functor is a type class with two operations: A => F[A] and F[A => B] => F[A] => F[B]. None of operations you mentioned has such signature. FoldLeft is more like Foldable. It's a different type class, a parent of Traversable (aka Traverse). And Traversable is connected with Applicative.
trait Functor[F[_]] {
def fmap[A, B](f: A => B)(fa: F[A]): F[B]
}
trait Applicative[F[_]] extends Functor[F] {
def pure[A](a: A): F[A]
def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
override def fmap[A, B](f: A => B)(fa: F[A]): F[B] = ap(pure(f))(fa)
}
trait Foldable[T[_]] {
def foldr[A, B](op: A => B => B)(seed: B)(ta: T[A]): B =
(foldMap(op)(ta) _)(seed)
def foldMap[A, M](f: A => M)(ta: T[A])(implicit monoid: Monoid[M]): M =
foldr[A, M](a => m => monoid.append(f(a), m))(monoid.empty)(ta)
}
trait Traversable[T[_]] extends Functor[T] with Foldable[T] {
def traverse[F[_]: Applicative, A, B](k: A => F[B])(ta: T[A]): F[T[B]] =
sequence[F, B](fmap[A, F[B]](k)(ta))
def sequence[F[_]: Applicative, A](tfa: T[F[A]]): F[T[A]] =
traverse[F, F[A], A](fa => fa)(tfa)
override def fmap[A, B](f: A => B)(ta: T[A]): T[B] = traverse[Id, A, B](f)(ta)
override def foldr[A, B](op: A => B => B)(seed: B)(ta: T[A]): B =
(traverse[Const[B => B]#λ, A, B](op)(ta) _)(seed)
override def foldMap[A, M: Monoid](f: A => M)(ta: T[A]): M =
traverse[Const[M]#λ, A, M](f)(ta)
}
type Id[A] = A
trait Const[C] {
type λ[A] = C
}
Type class Functor means you have a "container" F[_] and you know how to apply function f: A => B inside this container. Type class Applicative means you know how to pack a value a: A inside this container and how to apply a "function" F[A => B] to a "value" F[A]. Foldable means you know how to fold your container using binary operation A => B => B and starting value B and receiving result B. Traversable means you know how to traverse your container executing applicative effect A => F[B] in every "node".
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).
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(******************************************)
******************************************
Specifically, I'm trying to extend my Functor typeclass with Applicative.
trait Functor[F[_]] {
def fmap[A, B](r: F[A], f: A => B): F[B]
}
object Functor {
implicit class FunctorOps[A, F[_]: Functor](xs: F[A]) {
def fmap[B](f: A => B): F[B] = implicitly[Functor[F]].fmap(xs, f)
}
implicit def SeqFunctor: Functor[Seq] = new Functor[Seq] {
def fmap[A, B](r: Seq[A], f: A => B) = r map f
}
}
trait Applicative[F[_]] extends Functor[F] {
// What I want to do, but this *does not* work.
def fmap[A, B](r: F[A], f: A => B): F[B] = Functor.FunctorOps[A, F](r).fmap(f)
def pure[A](x: A): F[A]
def fapply[A, B](r: F[A], f: F[A => B]): F[B]
}
object Applicative {
implicit class ApplicativeOps[A, F[_]](a: F[A])(implicit F: Applicative[F]) {
def fapply[B](f: F[A => B]): F[B] = F.fapply(a, f)
}
implicit def SeqApplicative: Applicative[Seq] = new Applicative[Seq] {
def pure[A](x: A) = Seq(x)
def fapply[A, B](xs: Seq[A], fs: Seq[A => B]): Seq[B] = xs.flatMap(x => fs.map(_(x)))
}
}
The gist of it is I have to implement fmap for all Applicatives, but it should really be the same method as defined in my FunctorOps class. How do I do this in the cleanest way possible?
You got the Applicative[F] <: Functor[F] part right, but you should really think about what that means. It means that an instance of Applicative[F] also provides the methods for Functor[F]. That is, you can't have both implicit val listFunctor: Functor[List]; implicit val listApplicative: Applicative[List], because then the compiler is confused when you ask for implicit param: Functor[List]. You should only have the latter. What you're trying to do is then nonsensical, because you're defining the Functor instance for F in terms of itself (because the Applicative[F] should be the Functor[F]), and you end up with two Functor[Seq]s regardless.
What you can do is implement fmap in terms of pure and fapply:
trait Applicative[F[_]] extends Functor[F] {
override def fmap[A, B](r: F[A], f: A => B): F[B] = fapply(r, pure(f))
def pure[A](x: A): F[A]
def fapply[A, B](r: F[A], f: F[A => B]): F[B]
}
Then remove the Functor[Seq] instance and keep your Applicative[Seq] the way it is (or override fmap if you want). You have a different problem now, being that implicit search gets a bit turned around, as the Functor[Seq] instance is actually in object Applicative, but fixing implicit resolution is less onerous than enforcing the consistency of separate Functor and Applicative instances. In this case, where Seq is a type whose companion object you cannot control, cats, at least, does something like
package instances {
trait SeqInstances {
implicit val seqFunctor: Functor[Seq] = ???
}
package object seq extends SeqInstances
package object all extends SeqInstances
with AAAInstances
with BBBInstances
with ...
}
FYI: I suggest currying your typeclass methods
def fmap[A, B](r: F[A])(f: A => B): F[B]
def fapply[A, B](r: F[A])(f: F[A => B]): F[B]
and it may be nice to have a flip fapply in ApplicativeOps
def ylppaf[I, B](f: F[I])(implicit ev: A =:= (I => B))
: F[B] = F.fapply(a.fmap(ev))(f)
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[_].