Kotlin基础——Typeclass

2024-06-22 18:36
文章标签 基础 kotlin typeclass

本文主要是介绍Kotlin基础——Typeclass,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

高阶类型

如在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 = 1println(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 = thisreturn 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 = thisreturn "[" + 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(): Afun 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 = thisreturn 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 = thisval empty: Kind<List.K, B> = Nilreturn 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

这篇关于Kotlin基础——Typeclass的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1085082

相关文章

从基础到高级详解Python数值格式化输出的完全指南

《从基础到高级详解Python数值格式化输出的完全指南》在数据分析、金融计算和科学报告领域,数值格式化是提升可读性和专业性的关键技术,本文将深入解析Python中数值格式化输出的相关方法,感兴趣的小伙... 目录引言:数值格式化的核心价值一、基础格式化方法1.1 三种核心格式化方式对比1.2 基础格式化示例

redis-sentinel基础概念及部署流程

《redis-sentinel基础概念及部署流程》RedisSentinel是Redis的高可用解决方案,通过监控主从节点、自动故障转移、通知机制及配置提供,实现集群故障恢复与服务持续可用,核心组件包... 目录一. 引言二. 核心功能三. 核心组件四. 故障转移流程五. 服务部署六. sentinel部署

从基础到进阶详解Python条件判断的实用指南

《从基础到进阶详解Python条件判断的实用指南》本文将通过15个实战案例,带你大家掌握条件判断的核心技巧,并从基础语法到高级应用一网打尽,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录​引言:条件判断为何如此重要一、基础语法:三行代码构建决策系统二、多条件分支:elif的魔法三、

Python WebSockets 库从基础到实战使用举例

《PythonWebSockets库从基础到实战使用举例》WebSocket是一种全双工、持久化的网络通信协议,适用于需要低延迟的应用,如实时聊天、股票行情推送、在线协作、多人游戏等,本文给大家介... 目录1. 引言2. 为什么使用 WebSocket?3. 安装 WebSockets 库4. 使用 We

Kotlin 枚举类使用举例

《Kotlin枚举类使用举例》枚举类(EnumClasses)是Kotlin中用于定义固定集合值的特殊类,它表示一组命名的常量,每个枚举常量都是该类的单例实例,接下来通过本文给大家介绍Kotl... 目录一、编程枚举类核心概念二、基础语法与特性1. 基本定义2. 带参数的枚举3. 实现接口4. 内置属性三、

从基础到高阶详解Python多态实战应用指南

《从基础到高阶详解Python多态实战应用指南》这篇文章主要从基础到高阶为大家详细介绍Python中多态的相关应用与技巧,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、多态的本质:python的“鸭子类型”哲学二、多态的三大实战场景场景1:数据处理管道——统一处理不同数据格式

MySQL数据类型与表操作全指南( 从基础到高级实践)

《MySQL数据类型与表操作全指南(从基础到高级实践)》本文详解MySQL数据类型分类(数值、日期/时间、字符串)及表操作(创建、修改、维护),涵盖优化技巧如数据类型选择、备份、分区,强调规范设计与... 目录mysql数据类型详解数值类型日期时间类型字符串类型表操作全解析创建表修改表结构添加列修改列删除列

Python 函数详解:从基础语法到高级使用技巧

《Python函数详解:从基础语法到高级使用技巧》本文基于实例代码,全面讲解Python函数的定义、参数传递、变量作用域及类型标注等知识点,帮助初学者快速掌握函数的使用技巧,感兴趣的朋友跟随小编一起... 目录一、函数的基本概念与作用二、函数的定义与调用1. 无参函数2. 带参函数3. 带返回值的函数4.

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

Kotlin Map映射转换问题小结

《KotlinMap映射转换问题小结》文章介绍了Kotlin集合转换的多种方法,包括map(一对一转换)、mapIndexed(带索引)、mapNotNull(过滤null)、mapKeys/map... 目录Kotlin 集合转换:map、mapIndexed、mapNotNull、mapKeys、map