Kotlin基础——Typeclass

news/2024/6/30 6:51:17 标签: kotlin, windows, 开发语言

高阶类型

如在Iterable新增泛型方法时

interface Iterable<T> {
    fun filter(p: (T) -> Boolean): Iterable<T>
    fun remove(p: (T) -> Boolean): Iterable<T> = filter { x -> !p(x) }
}

对应的List、Set实现上述方法时仍需要返回具体的类型

interface List<T> : Iterable<T> {
    fun filter(p: (T) -> Boolean): List<T>
    fun remove(p: (T) -> Boolean): List<T> = filter { x -> !p(x) }
}

interface Set<T> : Iterable<T> {
    fun filter(p: (T) -> Boolean): Set<T>
    fun remove(p: (T) -> Boolean): Set<T> = filter { x -> !p(x) }
}

使用高阶类型可以解决上述问题,高阶类型指的是用类型构造新类型,Kotlin可以通过扩展实现高阶类型(下面例子都是根据这个来实现)

interface Kind<out F, out A>

sealed class List<out A> : Kind<List.K, A> {
    object K
}

inline fun <A> Kind<List.K, A>.unwrap(): List<A> = this as List<A>

object Nil : List<Nothing>()
data class Cons<A>(val head: A, val tail: List<A>) : List<A>()
  • Kind<out F, out A>表示类型构造器F应用类型参数A产生的新类型,F实际上不能携带类型参数
  • List.K是List的高阶类型,也就是说传入不同的A,根据List.K会有不同类型
  • unwrap()将Kind<List.K, A>类型转为List<A>进行操作
  • Nil为空列表用作尾部,Cons由元素head和及其指向tail构成的链表

Functor

Functor的map():通过f()方法将Kind<F, A>类型转为Kind<F, B>类型

interface Functor<F> {
    fun <A, B> Kind<F, A>.map(f: (A) -> B): Kind<F, B>
}

object ListFunctor : Functor<List.K> {
    override fun <A, B> Kind<List.K, A>.map(f: (A) -> B): Kind<List.K, B> {
        return when (this) {
            is Cons -> {
                val t = (this.tail.map(f)).unwrap()
                Cons<B>(f(this.head), t)
            }
            else -> Nil
        }
    }
}

使用方法如下,将Con<Int>转为了Con<String>

val cons: Cons<Int> = Cons(1, Nil)
println(cons.head::class)
println(cons.tail)
ListFunctor.run {
    val cons2: Cons<String> = cons.map { it.toString() } as Cons<String>
    println(cons2.head::class)
    println(cons2.tail)
}

打印如下

class kotlin.Int
com.demo.demo1.Nil@5361555
class kotlin.String
com.demo.demo1.Nil@5361555

Eq和ListEq

Eq

Eq根据传入的类型参数,对其制定比较规则

interface Eq<F> {
    fun F.eq(that: F): Boolean
}
object IntEq : Eq<Int> {
    override fun Int.eq(that: Int): Boolean {
        return this == that
    }
}

如上,对于Int,判断值是否相等,使用方法如下

IntEq.run {
    val a = 1
    println(a.eq(1))
    println(a.eq(2))
}

打印如下

true
false

ListEq

ListEq可根据指定类型参数的比较规则,实现对两个List比较

abstract class ListEq<A>(val a: Eq<A>) : Eq<Kind<List.K, A>> {
    override fun Kind<List.K, A>.eq(that: Kind<List.K, A>): Boolean {
        val curr = this
        return if (curr is Cons && that is Cons) {
            val headEq = a.run {
                curr.head.eq(that.head)
            }
            if (headEq) curr.tail.eq(that.tail) else false
        } else curr is Nil && that is Nil
    }
}
object IntListEq : ListEq<Int>(IntEq)

如上,实现IntListEq,使用方法如下

IntListEq.run {
    val a = Cons(1, Cons(2, Nil))
    val b = Cons(1, Cons(2, Nil))
    val c = Cons(1, Nil)
    println(a.eq(b))
    println(a.eq(c))
}

打印如下

true
false

show和Foldable

Show

show根据传入的类型参数,对其制定输出规则

interface Show<F> {
    fun F.show(): String
}
class Book(val name: String)
object BookShow : Show<Book> {
    override fun Book.show(): String = this.name
}

如上,对于Book,输出name属性,调用方法如下

BookShow.run {
    println(Book("Dive into Kotlin").show())
}

打印如下

Dive into Kotlin

Foldable

Foldable根据传入的类型参数,对其进行拼接(不太能理解这个fold的实现。。。)

interface Foldable<F> {
    fun <A, B> Kind<F, A>.fold(init: B): ((B, A) -> B) -> B
}
object ListFoldable : Foldable<List.K> {
    override fun <A, B> Kind<List.K, A>.fold(init: B): ((B, A) -> B) -> B = { f ->
        fun fold0(l: List<A>, v: B): B {
            return when (l) {
                is Cons -> {
                    fold0(l.tail, f(v, l.head))
                }
                else -> v
            }
        }
        fold0(this.unwrap(), init)
    }
}

ListShow

abstract class ListShow<A>(val a: Show<A>) : Show<Kind<List.K, A>> {
    override fun Kind<List.K, A>.show(): String {
        val fa = this
        return "[" + ListFoldable.run {
            fa.fold(listOf<String>())({ r, i ->
                r + a.run { i.show() }
            }).joinToString() + "]"
        }
    }
}
object BookListShow : ListShow<Book>(BookShow)

调用方法如下

BookListShow.run {
    println(
        Cons(
            Book("Dive into Kotlin"),
            Cons(Book("Thinking in Java"), Nil)
        ).show()
    )
}

打印如下

[Dive into Kotlin, Thinking in Java]

Monoid

Monoid满足结合律和同一律

interface Monoid<A> {
    fun zero(): A
    fun A.append(b: A): A
}

如对于字符串Monoid

  • 结合律:(“A”+“B”)+“C” == “A”+(“B”+“C”)
  • 同一律:“A”+“” == “A”
object StringConcatMonoid : Monoid<String> {
    override fun zero(): String = ""

    override fun String.append(b: String): String = this + b
}
fun <A> List<A>.sum(ma: Monoid<A>): A {
    val fa = this
    return ListFoldable.run {
        fa.fold(ma.zero())({ s, i ->
            ma.run {
                s.append(i)
            }
        })
    }
}

使用方式如下

println(
    Cons(
        "Dive ",
        Cons(
            "into ",
            Cons("Kotlin", Nil)
        )
    ).sum(StringConcatMonoid)
)

打印如下

Dive into Kotlin

Monad

Monad包含了最小的原始操作集合pure()和flatMap(),通过这两个组合,我们可以实现更复杂的数据转换操作

interface Monad<F> {
    fun <A> pure(a: A): Kind<F, A>
    fun <A, B> Kind<F, A>.flatMap(f: (A) -> Kind<F, B>): Kind<F, B>
}

如下实现ListMonad

object ListMonad : Monad<List.K> {
    private fun <A> append(fa: Kind<List.K, A>, fb: Kind<List.K, A>): Kind<List.K, A> {
        return if (fa is Cons) {
            Cons(fa.head, append(fa.tail, fb).unwrap())
        } else {
            fb
        }
    }

    override fun <A> pure(a: A): Kind<List.K, A> {
        return Cons(a, Nil)
    }

    override fun <A, B> Kind<List.K, A>.flatMap(f: (A) -> Kind<List.K, B>): Kind<List.K, B> {
        val fa = this
        val empty: Kind<List.K, B> = Nil
        return ListFoldable.run {
            fa.fold(empty)({ r, l ->
                append(r, f(l))
            })
        }
    }
}

Applicative

数学上3中代数结构关系如下Functor -> Applicative -> Monad

interface Functor<F> {
    fun <A, B> Kind<F, A>.map(f: (A) -> B): Kind<F, B>
}

interface Applicative<F> : Functor<F> {
    fun <A> pure(a: A): Kind<F, A>
    fun <A, B> Kind<F, A>.ap(f: Kind<F, (A) -> B>): Kind<F, B>
    override fun <A, B> Kind<F, A>.map(f: (A) -> B): Kind<F, B> {
        return ap(pure(f))
    }
}

interface Monad<F> : Applicative<F> {
    fun <A, B> Kind<F, A>.flatMap(f: (A) -> Kind<F, B>): Kind<F, B>
    override fun <A, B> Kind<F, A>.ap(f: Kind<F, (A) -> B>): Kind<F, B> {
        return f.flatMap { fn ->
            this.flatMap { a ->
                pure(fn(a))
            }
        }
    }
}

Option和OptionT

Kotlin中没有checked Exception,而是使用类型代替异常处理错误

Either和EitherT


http://www.niftyadmin.cn/n/5534614.html

相关文章

Java中的反射编程实用指南

Java中的反射编程实用指南 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天&#xff0c;我们将深入探讨Java中的反射编程。反射是Java提供的一种强大机制&am…

DDei在线设计器-API-DDeiFile

DDeiFile DDeiFile是代表一个设计文件&#xff0c;一个文件含有多个DDeiSheet(页签)。   DDeiFile实例包含了一个文件的所有数据&#xff0c;在获取后可以通过它访问其他内容。DDeiEditor中的files属性记录了当前打开的文件列表。 一个DDeiEditor实例至少包含一个DDeiFile实例…

创客项目秀|基于XIAO ESP32S3 sense 的小型相机

在这个科技飞速发展的时代&#xff0c;DIY&#xff08;Do It Yourself&#xff09;文化正成为连接创新与日常生活的桥梁&#xff0c;今天小编给大家带来了来自麻省理工学院的Arnov Sharma 的基于XIAO ESP32S3 sense的小型相机项目&#xff0c;该相机拥有一个圆形的触摸屏幕可以…

uni-app与原生插件混合开发调试3-安卓原生插件开发调试和打包

安卓原生插件开发调试和打包 上面已经介绍了怎么安装开发和调试环境&#xff0c;接下来就是安卓原生插件的具体开发和调试步骤&#xff1a; 将uniapp前端项目的index.vue文件新增代码。代码如图所示&#xff1a; <template><view><view><text>{{titl…

【问题记录】Ubuntu提示: “E: 软件包 gcc 没有可安装候选“

Ubuntu提示: "E: 软件包 gcc 没有可安装候选" 一&#xff0c;问题现象二&#xff0c;问题原因&解决方法 一&#xff0c;问题现象 在虚拟机Ubuntu中进行安装gcc命令时报错&#xff1a;“E: 软件包 gcc 没有可安装候选”: 二&#xff0c;问题原因&解决方法 …

计算机组成原理笔记-第4章 存储器

第4章 存储器 笔记PDF版本已上传至Github个人仓库&#xff1a;CourseNotes&#xff0c;欢迎fork和star&#xff0c;拥抱开源&#xff0c;一起完善。 该笔记是最初是没打算发网上的&#xff0c;所以很多地方都为了自我阅读方便&#xff0c;我理解了的地方就少有解释&#xff1b…

React+TS前台项目实战(十七)-- 全局常用组件Dropdown封装

文章目录 前言Dropdown组件1. 功能分析2. 代码详细注释3. 使用方式4. 效果展示 总结 前言 今天这篇主要讲全局Dropdown组件封装&#xff0c;可根据UI设计师要求自定义修改。 Dropdown组件 1. 功能分析 &#xff08;1&#xff09;通过position属性,可以控制下拉选项的位置 &am…

Python中文自然语言处理(NLP)中文分词工具库之pkuseg使用详解

概要 在中文自然语言处理(NLP)中,分词是一个基础且关键的任务。pkuseg 是由北京大学开发的一个中文分词工具,专为处理现代汉语而设计。它采用了先进的深度学习技术,能够准确地进行中文分词,同时支持自定义词典和多领域分词。本文将详细介绍 pkuseg 库,包括其安装方法、…