Skip to content

Instantly share code, notes, and snippets.

@latant
Created November 15, 2019 14:56
Show Gist options
  • Save latant/7c0f396c4e436b228fcddf7032d441d0 to your computer and use it in GitHub Desktop.
Save latant/7c0f396c4e436b228fcddf7032d441d0 to your computer and use it in GitHub Desktop.
Tiny implementation of lazy sequences
class Seq<out T>(val takeOne: () -> Pair<T, Seq<T>>?)
val nil: Seq<Nothing> = Seq { null }
fun <T> cons(head: T, tail: Seq<T> = nil) = Seq { Pair(head, tail) }
fun <T> list(vararg elements: T): Seq<T> {
var result: Seq<T> = nil
for (i in elements.indices.reversed())
result = cons(elements[i], result)
return result
}
tailrec fun <T> Seq<T>.forEach(consume: (T) -> Unit) {
val (head, tail) = takeOne() ?: return
consume(head)
tail.forEach(consume)
}
fun <A, B> Seq<A>.map(function: (A) -> B): Seq<B> = Seq {
takeOne()?.let { (h, t) -> Pair(function(h), t.map(function)) }
}
fun <T> Seq<T>.filter(predicate: (T) -> Boolean): Seq<T> = Seq {
var result = this.takeOne()
while(true) {
val (h, t) = result ?: break
if (predicate(h)) {
result = Pair(h, t.filter(predicate))
break
} else result = t.takeOne()
}
result
}
fun <T> Seq<T>.take(n: Int): Seq<T> = Seq {
if (n == 0) null else takeOne()?.let { (h, t) -> Pair(h, t.take(n - 1)) }
}
fun <A, B> Seq<A>.foldl(acc: B, function: (A, B) -> B): B {
var acc = acc
forEach { acc = function(it, acc) }
return acc
}
fun main() {
list(1, 3, 4, 5)
.map { println("$it + 1"); it + 1 }
.filter { println("$it even?"); it % 2 == 0 }
.take(2)
.foldl(0) { it, acc -> it + acc }
.let { println(it) }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment