DEV Community

Discussion on: Know When to Fold 'Em

Collapse
 
jbristow profile image
Jon Bristow • Edited

The (non arrow-kt) Kotlin version of some of these:


fun List<Boolean>.myOr() = foldRight(false, Boolean::or)

fun <A> List<A>.myAny(fn: (A) -> Boolean) =
    foldRight(false) { it, b -> b || fn(it) }

fun <A> List<A>.`myElem'`(a: A) = myAny { a == it }

fun <A> List<A>.myElem(a: A) = foldRight(false) { it, b -> b || (a == it) }

fun <A, B> List<A>.myMap(fn: (A) -> B) =
    foldRight(listOf<B>()) { it, list -> list + fn(it) }

I prefer Haskell, but my day job lets me do Kotlin, so I meet it halfway.

Also... as I did this, I realized that I prefer foldl most of the time because I started in Clojure with reduce which does the auto-lazy non-recursive left fold. (I think this is the equivalent of foldl' or 'strict left fold' in Haskell)

Can someone do the arrow-kt version so I can jumpstart my learnings and freak out the squares?

Collapse
 
deciduously profile image
Ben Lovy

Thanks for posting these! I'd really like to learn Kotlin.

Collapse
 
jbristow profile image
Jon Bristow • Edited

ok, I did the arrow-kt, and at this point it feels like I should just use Haskell.

import arrow.Kind
import arrow.core.Eval
import arrow.core.Option
import arrow.core.none
import arrow.core.some
import arrow.data.ListK
import arrow.data.k
import arrow.instances.listk.foldable.foldable
import arrow.instances.listk.monoid.monoid
import arrow.instances.monoid
import arrow.instances.option.foldable.foldable
import arrow.instances.option.monoid.monoid
import arrow.instances.semigroup
import arrow.typeclasses.Foldable
import arrow.typeclasses.Monoid

fun <F, A> myElem(foldableKind: Kind<F, A>, FO: Foldable<F>, elem: A) = FO.run {
    foldableKind.foldRight(Eval.False) { a, eval -> eval.map { it || (a == elem) } }.value()
}

fun <FA, A, B> myMap(k: Kind<FA, A>, FO: Foldable<FA>, MO: Monoid<B>, fn: (A) -> B): B {
    return FO.run {
        k.foldRight(Eval.now(MO.empty())) { a: A, eval: Eval<B> ->
            eval.map { MO.run { it + fn(a) } }
        }.value()
    }
}

fun main(args: Array<String>) {

    val a = myElem(none(), Option.foldable(), 123)
    // a:false
    println("a:$a")

    val b = myElem(123.some(), Option.foldable(), 123)
    // b:true
    println("b:$b")

    val c = myElem(listOf(1, 2, 123, 3).k(), ListK.foldable(), 123)
    // c:true
    println("c:$c")

    val d = myMap(listOf(1, 2, 3, 4).k(), ListK.foldable(), ListK.monoid()) { listOf("str:$it").k() }.list
    // d:[str:4, str:3, str:2, str:1]
    println("d:$d")

    val e = myMap(listOf(1, 2, 3, 4).k(), ListK.foldable(), Int.monoid(), 2::times)
    // e:20
    println("e:$e")

    val f = myMap(listOf(1, 2, 3, 4).k(), ListK.foldable(), Option.monoid(Int.semigroup())) {
        if (it > 2) (it + 5).some() else none()
    }
    // f:Some(17)
    println("f:$f")
}

I feel like I'm missing some idioms here on how to use arrow-kt properly. What we have here is myElem implemented so that any type that has a matching Foldable TypeClass can use this function. Maybe I need less toy examples?

I really don't like having to pass in utility objects just to tell it what kind of Monoid/Foldable I am. It's really showing off how strong Haskell's type system is.

Collapse
 
antonrich profile image
Anton

Have you tried Eta lang on android?

Collapse
 
jbristow profile image
Jon Bristow

Negatory, I'm a middle-to-backend developer. Currently, I'm using Kotlin to make developing with gremlin palatable while still having static typing. I'd use the python library, but Kotlin just feels more elegant to me.

Thread Thread
 
antonrich profile image
Anton

If you prefer Haskell than Eta lang could be the answer. Eta is Haskell on JVM.

I'm just curious what it would be like for you to try it out. Just your first impressions.

It may not work at all.
I'd try it myself but currently my beginning brain can't really learn one more thing (leaning Elm, Haskell, Elixir, html, css, postgres at the same time).