Skip to content
Snippets Groups Projects
Forked from intro-to-fp / short-exercises
28 commits behind the upstream repository.
Writer.scala 1010 B
package readerwriter.internal

import algebra.Monoid
import applicative.Monad

final case class Writer[L, A](v: (L, A))

object Writer {
  implicit def listMonoid[A]: Monoid[List[A]] = new Monoid[List[A]] {
    def zero: List[Nothing] = List.empty
    def op(l1: List[A], l2: List[A]): List[A] = l1 ++ l2
  }

  def tell[L](l: L): Writer[L, Unit] = Writer((l, ()))

  implicit def writerM[L: Monoid]: Monad[Writer[L, ?]] = new Monad[Writer[L, ?]] {
    override def flatMap[A, B](fa: Writer[L, A])(f: A => Writer[L, B]): Writer[L, B] = {
      val next = f(fa.v._2)
      Writer((implicitly[Monoid[L]].op(fa.v._1, next.v._1), next.v._2))
    }

    def unit[A](a: A): Writer[L, A] = Writer((implicitly[Monoid[L]].zero, a))
    override def map2[A, B, C](fa: Writer[L, A], fb: Writer[L, B])(f: (A, B) => C): Writer[L, C] =
      Writer((implicitly[Monoid[L]].op(fa.v._1, fb.v._1), f(fa.v._2, fb.v._2)))
    override def map[A, B](fa: Writer[L, A])(f: A => B): Writer[L, B] = Writer((fa.v._1, f(fa.v._2)))
  }
}