package readerwriter.internal

import algebra.Monoid
import applicative.Monad

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

object Writer:

  given [A]: Monoid[List[A]] with
    def zero: List[Nothing] = List.empty
    def combine(l1: List[A], l2: List[A]): List[A] = l1 ++ l2

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

  given writerMonad[L: Monoid]: Monad[[a] =>> Writer[L, a]] with
    def pure[A](a: A): Writer[L, A] = Writer((summon[Monoid[L]].zero, a))

    extension [A](fa: Writer[L, A])
      def flatMap[B](f: A => Writer[L, B]): Writer[L, B] =
        val next = f(fa.v._2)
        Writer((implicitly[Monoid[L]].combine(fa.v._1, next.v._1), next.v._2))

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