Module | Type classes |
arrow.typeclasses | Align, Apply, Eq, EqK, Foldable, Functor, FunctorFilter, Hash, Monoid, Semialign, Semigroup, Show, Traverse, Unalign, Unzip, Zip |
MapK
is an Arrow wrapper over Kotlin Map
type. The main goal is to make it a type constructor
and to work with Map
in more functional way.
It can be created by calling k()
function on Map:
import arrow.core.MapK
import arrow.core.k
import arrow.core.Eval
val arrowMap: MapK<String, Int> = mapOf("one" to 1, "two" to 2).k()
You can modify each map entry value and get another MapK with use of map(..)
function:
val arrowMap: MapK<String, Int> = mapOf("one" to 1, "two" to 2).k()
val modifiedMap: MapK<String, Int> = arrowMap.map { entryValue -> entryValue.plus(10) }
modifiedMap
// Map([(one, 11), (two, 12)])
Sometimes you need to “map” one Map to another. You are able to do so with map2(..)
function:
val firstBag: MapK<String, Int> = mapOf("eggs" to 5, "milk" to 1).k()
val secondBag: MapK<String, Int> = mapOf("eggs" to 6, "cheese" to 1).k()
val eggsBag: MapK<String, Int> = firstBag.map2(secondBag) { firstBagMatch, secondBagMatch ->
// If there are matching keys
firstBagMatch + secondBagMatch // you can modify the value of output MapK
}
map2Eval
does pretty much the same as map2
, but result KMap
will be wrapped in Eval
type.
ap
function is used when you want to apply map of transformations from Map<K, (A)-> B>
to Map<K,A>
. For example:
val map1: MapK<String, Int> = mapOf("one" to 1, "two" to 2).k()
val f1: (Int) -> String = { i: Int -> "f1 to \"$i\"" }
val f2: (Int) -> String = { i: Int -> "f2 to \"$i\"" }
val map2: MapK<String, (Int) -> String> = mapOf("one" to f1, "two" to f2).k()
val apResult = map1.ap(map2)
apResult
// Map([(one, f1 to "1"), (two, f2 to "2")])
ap2
acts like map2
to map
In most cases, you want to use flatMap
function, which flattens source map, accepts (A) -> MapK<K,B>
functor, and returns MapK<K,Z>
val map1: MapK<String, Int> = mapOf("one" to 1, "two" to 2).k()
val map2: MapK<String, String> = mapOf("one" to "ONE", "three" to "three").k()
val flattened: MapK<String, String> = map1.flatMap { map2 }
flattened
// Map([(one, ONE)])
foldLeft
and foldRight
are used for element aggregation:
import arrow.core.Eval
import arrow.core.MapK
import arrow.core.k
fun main() {
//sampleStart
val map1: MapK<String, Int> = mapOf("one" to 1, "two" to 2).k()
val foldLeft: String = map1.foldLeft("one") { entry, tuple -> entry + tuple }
val foldRight: Eval<String> =
map1.foldRight(Eval.just("one")) { entry, eval ->
Eval.just("$entry ${eval.value()}")
}
//sampleEnd
println(foldLeft)
println(foldRight)
}
You can also traverse MapK
data structure performing an action on each element:
import arrow.core.None
import arrow.core.Option
import arrow.core.Some
import arrow.core.extensions.option.applicative.applicative
import arrow.core.fix
import arrow.core.k
import arrow.core.some
fun main() {
//sampleStart
val optionMap = mapOf(1.some() to "one", 2.some() to "two", None to "none").k()
.traverse(Option.applicative()) { value ->
when (value) {
"one", "two", "none" -> Some(value)
else -> None
}
}.fix()
//sampleEnd
println(optionMap)
}
TODO: Add link to Traverse
docs when it’s ready https://github.com/arrow-kt/arrow/pull/1534
Do you like Arrow?
✖