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

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

package arrow.data

import arrow.*
import arrow.core.Either
import arrow.core.Eval
import arrow.core.Tuple2
import arrow.typeclasses.Applicative

fun  SequenceKWKind.toList(): List = this.ev().sequence.toList()

@higherkind
data class SequenceKW constructor(val sequence: Sequence) : SequenceKWKind, Sequence by sequence {

    fun  flatMap(f: (A) -> SequenceKWKind): SequenceKW = this.ev().sequence.flatMap { f(it).ev().sequence }.k()

    fun  ap(ff: SequenceKWKind<(A) -> B>): SequenceKW = ff.ev().flatMap { f -> map(f) }.ev()

    fun  map(f: (A) -> B): SequenceKW = this.ev().sequence.map(f).k()

    fun  foldLeft(b: B, f: (B, A) -> B): B = this.ev().fold(b, f)

    fun  foldRight(lb: Eval, f: (A, Eval) -> Eval): Eval {
        fun loop(fa_p: SequenceKW): Eval = when {
            fa_p.sequence.none() -> lb
            else -> f(fa_p.first(), Eval.defer { loop(fa_p.drop(1).k()) })
        }
        return Eval.defer { loop(this.ev()) }
    }

    fun  traverse(f: (A) -> HK, GA: Applicative): HK> =
            foldRight(Eval.always { GA.pure(emptySequence().k()) }) { a, eval ->
                GA.map2Eval(f(a), eval) { (sequenceOf(it.a) + it.b).k() }
            }.value()

    fun  map2(fb: SequenceKWKind, f: (Tuple2) -> Z): SequenceKW =
            this.ev().flatMap { a ->
                fb.ev().map { b ->
                    f(Tuple2(a, b))
                }
            }.ev()

    companion object {

        fun  pure(a: A): SequenceKW = sequenceOf(a).k()

        fun  empty(): SequenceKW = emptySequence().k()

        fun  tailRecM(a: A, f: (A) -> HK>): SequenceKW {
            tailrec fun  go(
                    buf: MutableList,
                    f: (A) -> HK>,
                    v: SequenceKW>) {
                if (!(v.toList().isEmpty())) {
                    val head: Either = v.first()
                    when (head) {
                        is Either.Right -> {
                            buf += head.b
                            go(buf, f, v.drop(1).k())
                        }
                        is Either.Left -> {
                            if (v.count() == 1)
                                go(buf, f, (f(head.a).ev()).k())
                            else
                                go(buf, f, (f(head.a).ev() + v.drop(1)).k())
                        }
                    }
                }
            }

            val buf = mutableListOf()
            go(buf, f, f(a).ev())
            return SequenceKW(buf.asSequence())
        }

    }
}

fun  SequenceKW.combineK(y: SequenceKWKind): SequenceKW = (this.sequence + y.ev().sequence).k()

fun  Sequence.k(): SequenceKW = SequenceKW(this)