i try to learn/understand a little bit of scalaz. For that i started with the example:
List(3, 4, 5).asMA.foldMap(x => x)
=> 12 //(3+4+5)
def foldMap[B](f: A => B)(implicit r: Foldable[M], m: Monoid[B])
So somewhere has to be an Foldable[List[_]] and a Monoid[Int] (with append = + and zero = 0). But i wasn't able to find these two implicits. Is there an easy way to find them?
Then the next example was:
List(3, 4, 5).asMA.foldMap(multiplication)
=> 60 //(3*4*5)
Here i get even more confused. I assumed that multiplication has to be replace the Monoid[Int] with one with append = *, zero = 1. But then f: A=>B is missing. And if i follow multiplication i don't find anything connected to a Monoid or function etc.
sealed trait IntMultiplication extends NewType[Int]
trait NewType[X] {
val value: X
override def toString = value.toString
}
There are some handy compiler flags when dealing with implicits: -Xlog-implicits
, -Xprint:typer
and -Ytyper-debug
In this case you can use -Xprint:typer
flag to see expressions with applied implicits. Then, first snippet List(3, 4, 5).asMA.foldMap(identity)
will expand to
scalaz.this.Scalaz.SeqMA[List, Int](immutable.this.List.apply[Int](3, 4, 5)).asMA.foldMap[Int]({
((x: Int) => scala.this.Predef.identity[Int](x))
})(scalaz.this.Foldable.ListFoldable,
scalaz.this.Monoid.monoid[Int](scalaz.this.Semigroup.IntSemigroup, scalaz.this.Zero.IntZero));
Now it is clear that
Monoid.monoid[Int](Semigroup.IntSemigroup, Zero.IntZero)
is used to create Monoid[Int]
instance (with append = + and zero = 0)
Second snippet, List(3, 4, 5).foldMap(multiplication)
will expand to
scalaz.this.Scalaz.SeqMA[List, Int](immutable.this.List.apply[Int](3, 4, 5)).foldMap[scalaz.IntMultiplication]({
((n: Int) => scalaz.Scalaz.multiplication(n))
})(scalaz.this.Foldable.ListFoldable,
scalaz.this.Monoid.monoid[scalaz.IntMultiplication](scalaz.this.Semigroup.IntMultiplicationSemigroup, scalaz.this.Zero.IntMultiplicationZero));
In this case Monoid[IntMultiplication]
(with append = * and zero = 1) is used as implicit parameter.
To create Monoid
for your type, you need to have implicit Semigroup
and Zero
in scope
case class Foo(x: Int)
implicit def FooSemigroup: Semigroup[Foo] = semigroup((f1, f2) => Foo(f1.x + f2.x))
implicit def FooZero: Zero[Foo] = zero(Foo(0))
scala> (1 to 10) map Foo foldMap identity
res5: Foo = Foo(55)
Scalaz 6 stores the typeclass instances in the companion objects of the typeclasses themselves, so you need to be looking there.
In the case of Monoid[T], the actual typeclass is splittable into two sections: Semigroup[T] provides us with the append operation (T, T) => T, Zero[T] provides us with a zero function: () => T. The actual Monoid instance can then be generated via the implicit def monoid living inside MonoidLow.
For foldable, the typeclass for Foldable[List] lives inside the Foldable singleton and is called ListFoldable.
As I'm sure you've worked out, the default monoid in scope for integers is (+, 0), so the multiplication function you've used in the second example is just a converter to the wrapper type IntMultiplication, which has semigroup and zero instances defined inside the relevant companion objects.
If you're trying to get your head around Scalaz, there's a couple of good introduction videos. The ones that I found most useful were these two:
[1] http://skillsmatter.com/podcast/scala/practical-scalaz-2518/js-1603
[2] http://www.infoq.com/presentations/Scalaz-Functional-Programming-in-Scala#.T0q_hgmiJbw.wordpress
Both of which touch on monoids.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With