kata_Kata –在Kotlin中实现功能性List数据结构

kata

我在出色的Scala函数式编程》一书的第3章中看到了一个练习,该练习处理了定义函数数据结构的问题,并使用链表作为示例来说明如何开发这种数据结构。 我想使用Kotlin尝试该示例,以了解我可以在多大程度上复制该示例。

样品的Scala的骨架可在同伴码书在这里和我在Kotlin尝试通过信息库中的大量answerkey启发(复制!)。

基本的

这是Kotlin中基本的List表示形式:

sealed class List<out A> {

    abstract val head: A

    abstract val tail: List<A>
}

data class Cons<out T>(override val head: T, override val tail: List<T>) : List<T>()

object Nil : List<Nothing>() {
    override val head: Nothing
        get() {
            throw NoSuchElementException("head of an empty list")
        }

    override val tail: List<Nothing>
        get() {
            throw NoSuchElementException("tail of an empty list")
        }
}

List已定义为密封类,这意味着密封类的所有子类都将在同一文件中定义。 这对于实例类型的模式匹配很有用,并且在大多数功能中都会反复出现。

此列表有两种实现方式–

1.包含一个由头部元素和尾部列表组成的非空列表,

2.空列表

就目前的形式而言,这已经非常有用,请考虑以下内容以构造一个List并从中检索元素:

val l1:List<Int> = Cons(1, Cons(2, Cons(3, Cons(4, Nil))))
assertThat(l1.head).isEqualTo(1)
assertThat(l1.tail).isEqualTo(Cons(2, Cons(3, Cons(4, Nil))))


val l2:List<String> = Nil

模式匹配“何时”表达

现在跳到实现List的一些方法。 由于List是一个密封的类,因此它允许一些良好的模式匹配,例如,获取List中元素的总和:

fun sum(l: List<Int>): Int {
    return when(l) {
        is Cons -> l.head + sum(l.tail)
        is Nil -> 0
    }
}

编译器知道Cons和Nil是列表实例上进行匹配的仅有两条路径。

稍微复杂一点的操作是,从列表的开头“删除”一些元素,然后“ dropWhile”接收一个谓词,然后从与该谓词匹配的开头删除元素:

fun drop(n: Int): List<A> {
    return if (n <= 0)
        this
    else when (this) {
        is Cons -> tail.drop(n - 1)
        is Nil -> Nil
    }
}

val l = list(4, 3, 2, 1)
assertThat(l.drop(2)).isEqualTo(list(2, 1))

fun dropWhile(p: (A) -> Boolean): List<A> {
    return when(this) {
        is Cons -> if (p(this.head)) this.tail.dropWhile(p) else this
        is Nil -> Nil
    }
}

val l = list(1, 2, 3, 5, 8, 13, 21, 34, 55, 89)
assertThat(l.dropWhile({e -> e < 20})).isEqualTo(list(21, 34, 55, 89))

这些展示了模式匹配和Kotlin中“ when”表达的强大功能。

不安全的差异!

要抚平皱纹,请查看如何使用声明为“ out T”的类型参数定义List,这被称为“声明位点差异”,在这种情况下,它使List在类型T上协变。 Kotlin文档对它进行了精美的解释。 使用List声明的方式,它使我可以执行以下操作:

val l:List<Int> = Cons(1, Cons(2, Nil))
val lAny: List<Any> = l

现在,考虑一个“附加”功能,该功能附加另一个列表:

fun append(l: List<@UnsafeVariance A>): List<A> {
    return when (this) {
        is Cons -> Cons(head, tail.append(l))
        is Nil -> l
    }
}

这里,将第二个列表作为附加函数的参数,但是Kotlin会标记该参数–这是因为可以返回协变量类型,但不能将其作为参数。 但是,由于我们知道List的当前形式是不可变的,因此可以通过在类型参数上标记“ @UnsafeVariance”注释来克服此问题。

折叠式

折叠操作允许基于列表中各个元素的某种聚合将列表“折叠”为结果。

考虑foldLeft:

fun <B> foldLeft(z: B, f: (B, A) -> B): B {
    tailrec fun foldLeft(l: List<A>, z: B, f: (B, A) -> B): B {
        return when (l) {
            is Nil -> z
            is Cons -> foldLeft(l.tail, f(z, l.head), f)
        }
    }

    return foldLeft(this, z, f)
}

如果列表由元素(2、3、5、8)组成,则foldLeft等效于“ f(f(f(f(f(z,2),3),5),8)”

有了这个高阶函数,求和函数可以这样表示:

val l = Cons(1, Cons(2, Cons(3, Cons(4, Nil))))
assertThat(l.foldLeft(0, {r, e -> r + e})).isEqualTo(10)

foldRight在Kotlin中如下所示:

fun <B> foldRight(z: B, f: (A, B) -> B): B {
    return when(this) {
        is Cons -> f(this.head, tail.foldRight(z, f))
        is Nil -> z
    }
}

如果列表由元素(2、3、5、8)组成,则foldRight等效于“ f(2,f(3,f(5,f(8,z,))))”

这个版本的foldRight尽管看上去不是很酷的尾部递归,但是可以通过使用先前定义的尾部递归foldLeft来实现更友好的堆栈版本,方法是简单地反转List并以下列方式在内部调用foldLeft:

fun reverse(): List<A> {
    return foldLeft(Nil as List<A>, { b, a -> Cons(a, b) })
}

fun <B> foldRightViaFoldLeft(z: B, f: (A, B) -> B): B {
    return reverse().foldLeft(z, { b, a -> f(a, b) })
}

地图和flatMap

map是转换此列表元素的函数:

fun <B> map(f: (A) -> B): List<B> {
    return when (this) {
        is Cons -> Cons(f(head), tail.map(f))
        is Nil -> Nil
    }
}

以下是使用此功能的一个示例:

val l = Cons(1, Cons(2, Cons(3, Nil)))
val l2 = l.map { e -> e.toString() }
assertThat(l2).isEqualTo(Cons("1", Cons("2", Cons("3", Nil))))

map的一种变体,其中转换函数返回另一个列表,最终结果使所有内容变平,最好在实现后使用示例进行演示:

fun <B> flatMap(f: (a: A) -> List<@UnsafeVariance B>): List<B> {
    return flatten(map { a -> f(a) })
}

companion object {
    fun <A> flatten(l: List<List<A>>): List<A> {
        return l.foldRight(Nil as List<A>, { a, b -> a.append(b) })
    }
}


val l = Cons(1, Cons(2, Cons(3, Nil)))

val l2 = l.flatMap { e -> list(e.toString(), e.toString()) }

assertThat(l2)
        .isEqualTo(
                Cons("1", Cons("1", Cons("2", Cons("2", Cons("3", Cons("3", Nil)))))))

这涵盖了使用Kotlin实现功能列表数据结构所涉及的基础知识,与scala版本相比,存在一些粗糙之处,但我认为它大部分都可以工作。 诚然,可以对样本进行大幅度的改进,如果您对如何改进代码有任何意见,请务必给我发送PR
github回购此样本或作为对此文章的评论。

翻译自: https://www.javacodegeeks.com/2017/10/kata-implementing-functional-list-data-structure-kotlin.html

kata

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 事实上,isulad容器引擎是支持kata安全容器的。isulad是一个开源的轻量级容器运行时,它可以与不同的容器技术进行集成,包括kata。kata是一个基于虚拟化技术的安全容器,它可以提供更高的安全性和隔离性。isulad集成了kata,可以使用kata安全容器来运行容器。这样可以在保持轻量级的同时,提供更高的安全性。 ### 回答2: isulad容器引擎是一款在国开发的轻量级容器引擎,主要用于在Linux操作系统上运行容器。它的设计目标是为了提供高性能、高可靠性和高扩展性的容器运行环境。然而,目前isulad容器引擎并不支持kata安全容器。 kata安全容器是一种基于虚拟化技术的安全容器方案。它通过在每个容器实例内部运行一个轻量级虚拟机来提供隔离和安全性。kata容器与传统容器相比,能够提供更高的安全性和隔离性,保护容器内部的数据和环境免受攻击和恶意代码的侵害。 尽管kata容器在安全性方面具有很大优势,但由于技术实现上的差异,isulad容器引擎并不支持它。这意味着在使用isulad容器引擎时,无法直接使用kata容器提供的安全特性。 如果用户需要使用kata安全容器,可以考虑使用其他容器引擎,例如Docker或者Kubernetes,它们都提供了对kata容器的支持。通过使用这些容器引擎,用户可以轻松地创建、部署和管理kata容器,同时享受到kata容器提供的额外安全性和隔离性。 ### 回答3: isulad容器引擎目前不支持kata安全容器。isulad是华为公司开源的一款容器运行时引擎,它主要用于在Linux操作系统上创建和管理容器实例。isulad注重轻量性和高性能,提供了一系列功能丰富的容器管理工具和API,以满足用户对容器化应用的需求。 但是,isulad并不支持kata安全容器。kata是一个针对安全性和性能进行优化的容器运行时,它采用虚拟化技术,通过在宿主机上创建虚拟机来运行容器,提供了更高的隔离性和安全性。 尽管kata安全容器具有许多优点,但是isulad目前还没有整合kata运行时的能力。这可能是因为isulad的设计目标和使用场景与kata不完全一致,或者是因为isulad的开发者团队还没有将kata集成到isulad。因此,如果用户有需要在isulad使用kata安全容器的需求,可能需要考虑其他容器引擎或解决方案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值