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

arrow.data.ListKW.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.Eval
import arrow.core.Option
import arrow.core.Tuple2
import arrow.typeclasses.Applicative

@higherkind
data class ListKW constructor(val list: List) : ListKWKind, List by list {

    fun  flatMap(f: (A) -> ListKWKind): ListKW = this.ev().list.flatMap { f(it).ev().list }.k()

    fun  map(f: (A) -> B): ListKW = this.ev().list.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: ListKW): Eval = when {
            fa_p.list.isEmpty() -> lb
            else -> f(fa_p.ev().list.first(), Eval.defer { loop(fa_p.list.drop(1).k()) })
        }
        return Eval.defer { loop(this.ev()) }
    }

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

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

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

    fun  mapFilter(f: (A) -> Option): ListKW =
            flatMap({ a -> f(a).fold({ empty() }, { pure(it) }) })

    companion object {

        fun  pure(a: A): ListKW = listOf(a).k()

        fun  empty(): ListKW = emptyList().k()

        @Suppress("UNCHECKED_CAST")
        private tailrec fun  go(
                buf: ArrayList,
                f: (A) -> HK>,
                v: ListKW>) {
            if (!v.isEmpty()) {
                val head: Either = v.first()
                when (head) {
                    is Either.Right -> {
                        buf += head.b
                        go(buf, f, v.drop(1).k())
                    }
                    is Either.Left -> go(buf, f, (f(head.a).ev() + v.drop(1)).k())
                }
            }
        }

        fun  tailRecM(a: A, f: (A) -> HK>): ListKW {
            val buf = ArrayList()
            go(buf, f, f(a).ev())
            return ListKW(buf)
        }
    }

}

fun  ListKW.combineK(y: ListKWKind): ListKW = (this.list + y.ev().list).k()

fun  List.k(): ListKW = ListKW(this)