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

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

package arrow.data

import arrow.*
import arrow.core.*
import arrow.typeclasses.Applicative
import arrow.typeclasses.Foldable

@higherkind
data class MapKW(val map: Map) : MapKWKind, Map by map {

    fun  map(f: (A) -> B): MapKW = this.map.map { it.key to f(it.value) }.toMap().k()

    fun  map2(fb: MapKW, f: (A, B) -> Z): MapKW =
            if (fb.isEmpty()) emptyMap().k()
            else this.map.flatMap {
                (k, a) ->
                fb.getOption(k).map { Tuple2(k, f(a, it)) }.k().asIterable()
            }.k()

    fun  map2Eval(fb: Eval>, f: (A, B) -> Z): Eval> =
            if (fb.value().isEmpty()) Eval.now(emptyMap().k())
            else fb.map { b -> this.map2(b, f) }

    fun  ap(ff: MapKW B>): MapKW =
            ff.flatMap { this.map(it) }

    fun  ap2(f: MapKW Z>, fb: MapKW): Map =
            f.map.flatMap {
                (k, f) ->
                this.flatMap { a -> fb.flatMap { b -> mapOf(Tuple2(k, f(a, b))).k() } }
                        .getOption(k).map { Tuple2(k, it) }.k().asIterable()
            }.k()

    fun  flatMap(f: (A) -> MapKW): MapKW =
            this.map.flatMap {
                (k, v) ->
                f(v).getOption(k).map { Tuple2(k, it) }.k().asIterable()
            }.k()

    fun  foldRight(b: Eval, f: (A, Eval) -> Eval): Eval = this.map.values.iterator().iterateRight(b)(f)

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

    fun  foldLeft(b: MapKW, f: (MapKW, Tuple2) -> MapKW): MapKW =
            this.map.foldLeft(b) { m, (k, v) -> f(m.k(), Tuple2(k, v)) }.k()

    fun  traverse(f: (A) -> HK, GA: Applicative): HK> =
            (Foldable.iterateRight(this.map.iterator(), Eval.always { GA.pure(emptyMap().k()) }))({ kv, lbuf ->
                GA.map2Eval(f(kv.value), lbuf) { (mapOf(kv.key to it.a).k() + it.b).k() }
            }).value()

    companion object
}

fun  Map.k(): MapKW = MapKW(this)

fun  Option>.k(): MapKW =
        when (this) {
            is Some -> mapOf(this.t).k()
            is None -> emptyMap().k()
        }

fun  List>.k(): MapKW = this.map { it.key to it.value }.toMap().k()

fun  Map.getOption(k: K): Option = Option.fromNullable(this[k])

fun  MapKW.updated(k: K, value: A): MapKW {
    val mutableMap = this.toMutableMap()
    mutableMap.put(k, value)

    return mutableMap.toMap().k()
}

fun  Map.foldLeft(b: Map, f: (Map, Map.Entry) -> Map): Map {
    var result = b
    this.forEach { result = f(result, it) }
    return result
}

fun  Map.foldRight(b: Map, f: (Map.Entry, Map) -> Map): Map =
    this.entries.reversed().k().map.foldLeft(b) { x, y -> f(y, x) }

fun  Iterator.iterateRight(lb: Eval): (f: (A, Eval) -> Eval) -> Eval = Foldable.iterateRight(this, lb)

fun  mapOf(vararg tuple: Tuple2): Map = if (tuple.isNotEmpty()) tuple.map { it.a to it.b }.toMap() else emptyMap()