All Downloads are FREE. Search and download functionalities are using the official Maven repository.

arrow.data.WriterT.kt Maven / Gradle / Ivy

There is a newer version: 0.8.2
Show newest version
package arrow.data

import arrow.*
import arrow.core.Either
import arrow.core.Tuple2
import arrow.core.toT
import arrow.typeclasses.*

@Suppress("UNCHECKED_CAST") inline fun  WriterTKind.value(): HK> = this.ev().value

@higherkind data class WriterT(val value: HK>) : WriterTKind, WriterTKindedJ {

    companion object {

        inline fun  pure(a: A, MM: Monoid = monoid(), AF: Applicative = applicative()) =
                WriterT(AF.pure(Tuple2(MM.empty(), a)))

        inline fun  both(w: W, a: A, MF: Monad = monad()) = WriterT(MF.pure(Tuple2(w, a)))

        inline fun  fromTuple(z: Tuple2, MF: Monad = monad()) = WriterT(MF.pure(z))

        operator fun  invoke(value: HK>): WriterT = WriterT(value)

        inline fun  putT(vf: HK, w: W, FF: Functor = functor()): WriterT =
                WriterT(FF.map(vf, { v -> Tuple2(w, v) }))

        inline fun  put(a: A, w: W, applicativeF: Applicative = applicative()): WriterT =
                putT(applicativeF.pure(a), w)

        fun  putT2(vf: HK, w: W, FF: Functor): WriterT =
                WriterT(FF.map(vf, { v -> Tuple2(w, v) }))

        fun  put2(a: A, w: W, AF: Applicative): WriterT =
                putT2(AF.pure(a), w, AF)

        inline fun  tell(l: W): WriterT = put(Unit, l)

        fun  tell2(l: W, AF: Applicative): WriterT = put2(Unit, l, AF)

        inline fun  value(v: A, monoidW: Monoid = monoid()):
                WriterT = put(v, monoidW.empty())

        inline fun  valueT(vf: HK, monoidW: Monoid = monoid()): WriterT =
                putT(vf, monoidW.empty())

        inline fun  empty(MMF: MonoidK = monoidK()): WriterTKind = WriterT(MMF.empty())

        fun  pass(fa: HK, Tuple2<(W) -> W, A>>, MF: Monad): WriterT =
                WriterT(MF.flatMap(fa.ev().content(MF), { tuple2FA -> MF.map(fa.ev().write(MF), { l -> Tuple2(tuple2FA.a(l), tuple2FA.b) }) }))

        fun  tailRecM(a: A, f: (A) -> HK, Either>, MF: Monad): WriterT =
                WriterT(MF.tailRecM(a, {
                    MF.map(f(it).ev().value) {
                        val value = it.b
                        when (value) {
                            is Either.Left -> Either.Left(value.a)
                            is Either.Right -> Either.Right(it.a toT value.b)
                        }
                    }
                }))
    }

    fun tell(w: W, SG: Semigroup, MF: Monad): WriterT = mapAcc ({ SG.combine(it, w) }, MF)

    fun listen(MF: Monad): HK, Tuple2> =
            WriterT(MF.flatMap(content(MF), { a -> MF.map(write(MF), { l -> Tuple2(l, Tuple2(l, a)) }) }))

    fun content(FF: Functor): HK = FF.map(value, { it.b })

    fun write(FF: Functor): HK = FF.map(value, { it.a })

    fun reset(MM: Monoid, MF: Monad): WriterT = mapAcc ({ MM.empty() }, MF)

    fun  map(f: (A) -> B, FF: Functor): WriterT = WriterT(FF.map(value, { it.a toT f(it.b) }))

    inline fun  mapAcc(crossinline f: (W) -> U, MF: Monad): WriterT = transform ({ f(it.a) toT it.b }, MF)

    inline fun  bimap(crossinline g: (W) -> U, crossinline f: (A) -> C, MF: Monad): WriterT = transform ({ g(it.a) toT f(it.b) }, MF)

    fun swap(MF: Monad): WriterT = transform({ it.b toT it.a }, MF)

    fun  ap(ff: WriterTKind B>, SG: Semigroup, MF: Monad): WriterT =
            ff.ev().flatMap({ map(it, MF) }, SG, MF)

    inline fun  flatMap(crossinline f: (A) -> WriterT, SG: Semigroup, MF: Monad): WriterT =
            WriterT(MF.flatMap(value, { value -> MF.map(f(value.b).value, { SG.combine(it.a, value.a) toT it.b }) }))

    inline fun  transform(crossinline f: (Tuple2) -> Tuple2, MF: Monad): WriterT = WriterT(MF.flatMap(value, { MF.pure(f(it)) }))

    fun  liftF(fa: HK, AF: Applicative): WriterT = WriterT(AF.map2(fa, value, { it.b.a toT it.a }))

    inline fun  semiflatMap(crossinline f: (A) -> HK, SG: Semigroup, MF: Monad): WriterT = flatMap({ liftF(f(it), MF) }, SG, MF)

    inline fun  subflatMap(crossinline f: (A) -> Tuple2, MF: Monad): WriterT = transform({ f(it.b) }, MF)

    fun combineK(y: WriterTKind, SF: SemigroupK): WriterT =
            WriterT(SF.combineK(value, y.ev().value))
}