Functional Kotlin : lambdas and sealed class list

I am learning Kotlin and functional programming. I have to implement own functions for a stealed class list to get a deep understanding of higher functions.

This is the code of the stealed class

sealed class List <T> {

 class Node <T> (val head : T, val tail : List<T>) : List<T> () {
    override fun toString () =
        "${head.toString()} , ${tail.toString()}"
}

object Nil : List<Nothing> ()  {
    override fun toString () = "NIL"
}


companion object {
    operator
    fun <T> invoke (vararg values : T ) : List<T>{
        val empty = Nil as List<T>
        val res = values.foldRight( empty , { v, l -> l.addFirst(v)   })
        return res
    }
}

fun addFirst ( head : T ) : List<T> = Node (head , this)

fun removeFirst ()  : List <T> = when (this) {
    is Nil -> throw IllegalStateException()
    is Node<T> -> this.tail
}

}

This is one of my implemented functions for filtering the sealed class list

fun <T> filter (element: List<T>, predicate:(T) -> Boolean) : List<T> = when (element) {
is List.Nil -> List.Nil as List<T> //do nothing
is List.Node -> element.tail.filter {predicate(it)}

}

I have used a working example

fun findNumbers(numbers: List<Int>, predicate: (Int) -> (Boolean)): List<Int> =
numbers.filter { predicate(it) } for a simple list

And now I am not able to figure out, why this doesn’t work with a sealed class. Any ideas?

1 Like

My guess is that in some way you are mixing up List(your own implementation) and kotlin.List(the kotlin list interface).
Is your findNumbers function in the same file as your List class? If not, you should check your imports. Also if I were you I would rename List to MyList, that way you can’t confuse your implementation with kotlin.List.

You are right. This is the new code

fun <T> MyList<T>.filtering (predicate:(T) -> Boolean) : MyList<T> = when (this) {
MyList.Nil -> MyList.Nil as MyList<T>
is MyList.Node -> tail.filtering{predicate(head)}

}

But still the result is only “Nil”

val liste1 = MyList<Int>(2,3,4,5,5,5)
val probFilter = liste1.filtering {it == 4}

→ Filter: NIL

That’s because you are not actually using the predicate anywhere. Try this instead:

fun <T> MyList<T>.filtering (predicate:(T) -> Boolean) : MyList<T> = when (this) {
  Nil -> this
  is Node -> 
    if(predicate(head))
      Node(head, tail.filtering(predicate)) 
    else tail.filtering(predicate)
}

BTW, consider making it covariant, ie. sealed class MyList <out T>. You will have to make addFirst an extension, though.

1 Like

Works fine. Thank you very much!