scala with cats 之 Contravariant Functors and Invariant Functors
Contravariant Functors
概述
Functor的意思是,如果有个F[A]和函数A=>B,那么就能得到一个F[B]。而Contravariant Functors的意思是,如果有个F[B],然后有个函数A => B,那我们就能得到一个F[A]。
用途
假如我们有个类型类,比如说
trait Semigroup[A]{def combine(x:A,y:A):A
}
我们经常要定义各种实例,比如Semigroup[Int],Semigroup[String],比如Semigroup[Boolean]。这些都是cats内置的实例。如果我们自己有个类型Box,我们要自己定义Semigroup[Box]实例。可是自己定义实例实在太麻烦,能不能根据现有的实例转化成新的实例呢?当然是是可以的。
示例
还是拿cats里面的例子讲解。
先定义类型类,然后给个contramap实现:
trait Printable[A] {def format(value: A): Stringdef contramap[B](func: B => A): Printable[B] =new Printable[B] {def format(value: B): String =self.format(func(value))}
}
理论上contramap并不是Printable本身的能力,其实应该属于Contravariant[F[_]]的能力。所以单独实现一个Contravariant[Printable]实例比较好,类似下面的Contravariant[Show]:
implicit val catsContravariantForShow: Contravariant[Show] = new Contravariant[Show] {def contramap[A, B](fa: Show[A])(f: B => A): Show[B] =show[B]((fa.show _).compose(f))}
- 假设我们已经有两个实例
Printable[Int]
和Printable[Boolean]
implicit val stringPrintable: Printable[String] =new Printable[String] {def format(value: String): String =s"'${value}'"}implicit val booleanPrintable: Printable[Boolean] =new Printable[Boolean] {def format(value: Boolean): String =if(value) "yes" else "no"}
- 现在有个case class
// Box有个类型参数
final case class Box[A](value: A)
3.定义Printable[Box[A]]的实例
// 方法一 自己实现
implicit def boxPrintable[A](implicit p: Printable[A]
): Printable[Box[A]] =new Printable[Box[A]] {def format(box: Box[A]): String =p.format(box.value)}
// 方法二 通过contramap方法实现,就不必每次都去写很多模板代码implicit def boxPrintable[A](implicit p: Printable[A]): Printable[Box[A]] =p.contramap[Box[A]](_.value)
Invariant Functors
概述
Invariant Functors 说起来虽然神秘,但是在scala的领域确是非常的常见。很多数据库的包,比如slick,quill等。经常我们要把scala程序里面定义的case class 转为字符串写到数据库,还需要把数据库里面的字符串转为程序需要的case class。
作为标准库的设计者会明白,case class 是无限的,但是组成case class 的元素时有限的,就是 scala 的基本内置类型。而数据库只需要和这些基本内置类型对接好就行了,用户负责将case class 转为基本内置类型。
示例
假设现在设计一个标志库,和数据库交互方法如下(转成字符串就算写入数据库):
def encode[A](value: A)(implicit c: Codec[A]): String =c.encode(value)def decode[A](value: String)(implicit c: Codec[A]): A =c.decode(value)
抽象Codec[A]
使用encode和decode,理论上能把任意的类型A写入数据库,也能把数据库的数据读成任意类型A,只需要提供类型A的Codec实例即可。Codec签名如下:
trait Codec[A] { self =>def encode(value: A): Stringdef decode(value: String): Adef imap[B](dec: A => B, enc: B => A): Codec[B] = {new Codec[B] {def encode(value: B): String =self.encode(enc(value))def decode(value: String): B =dec(self.decode(value))}}
}
添加内置实例
前面说过,case class 是无限的,但是组成case class的元素是有限的,现在在标准库中添加这些有限的内置示例。
implicit val stringCodec: Codec[String] =new Codec[String] {def encode(value: String): String = valuedef decode(value: String): String = value}implicit val doubleCodec: Codec[Double] =stringCodec.imap[Double](_.toDouble, _.toString)implicit val intCodec: Codec[Int] =stringCodec.imap(_.toInt, _.toString)implicit val booleanCodec: Codec[Boolean] =stringCodec.imap(_.toBoolean, _.toString)
用户自己实现自己的case class 实例
implicit def boxCodec[A](implicit c: Codec[A]): Codec[Box[A]] =c.imap[Box[A]](Box(_), _.value)
将自己的实例写入数据库或者从数据库读出来(假设转成字符串就算写入数据库)
encode(Box(123.4))
// res13: String = "123.4"
decode[Box[Double]]("123.4")
// res14: Box[Double] = Box(123.4)
scala with cats 之 Contravariant Functors and Invariant Functors相关推荐
- 协变 (Covariant)、逆变 (Contravariant) 与不变 (Invariant)
协变(Covariant).逆变(Contravariant)与不变(Invariant) 1. 定义 2. 例子 3. 有什么用? 4. 应对 5. 其他问题 6. 特例(Dart 语言) 7. 写 ...
- scala 协变和逆变_Scala方差:协变,不变和逆变
scala 协变和逆变 In this post, we are going to discuss about Scala Variance and it's use cases. 在本文中,我们将讨 ...
- 学习Scala — 8个不做和7个不做
Today I would like to share with you my view on learning Scala, what approach to take, what to do an ...
- lockfree buffer test
性能测试(3): 对无锁队列boost::lockfree::queue和moodycamel::ConcurrentQueue做一个性能对比测试 版权声明:本文为博主zieckey原创文章,转载时请 ...
- 29muduo_net库源码分析(五)
1.进程(线程)wait/notify (1)pipe (2)socketpair (3)eventfd,eventfd是一个比 pipe更高效的线程间事件通知机制,一方面它比 pipe 少用一个fi ...
- Linux中锁的总结
目录 1 前言 2 注意事项 2.1 明确锁的范围 2.2 减少锁的粒度 3 避免死锁的建议 1 前言 实际开发过程中,使用锁会带来一定性能的损失,但如果使用锁也能满足性能要求,对于锁的使用就无妨.使 ...
- 【 C++ 技术】 C++ 高性能服务器网络框架设计细节
作者:范蠡 原文:C++ 高性能服务器网络框架设计细节 前言 这篇文章我们将介绍服务器的开发,并从多个方面探究如何开发一款高性能高并发的服务器程序.需要注意的是一般大型服务器,其复杂程度在于其业务, ...
- muduo源码剖析——以三个切片浅析muduo库代码设计的严谨性、高效性与灵活性
0 前言 陈硕大佬的muduo网络库的源码我已经看了好久了,奈何本人实力有限,每每看到其代码设计的精巧之处只能内心称赞,无法用言语表达出来.实在令人汗颜.最近在看到网络设计部分时有了一些体会,结合自己 ...
- muduo网络库浅谈(一)
muduo网络库浅谈(一) 序言 第一章 muduo的关键结构 class EventLoop class Channel class Poller 番外 定时任务 class Timestamp c ...
最新文章
- NC19814最短路 LCA+bfs暴力
- mysql 全局变量_详细讲解mysql全局变量与局部变量
- python读取扫描形成的pdf_Python利用PyPDF2库获取PDF文件总页码实例
- vb6 获取zip列表_深入学习redis(压缩列表)
- windows添加删除程序打不开解决方案
- jquery获取动态表格行号_jquery得到表格当前行数据
- 做一个小淘气轮廓--文章和论文专辑
- Java后端Controller层解析Json数组转对象
- Sniffer和网络执法官软件助你维护网络
- 学生管理系统IPO图_玩不起了?海底捞取消大学生69折优惠,海底捞:暂不会调整...
- bam文件读取_科学网—Pacbio Sequel两种bam文件解析 - 卢锐的博文
- 阿里云ECS部署L2TP/IPSEC,访问服务器内网
- 计算机工作自动化的特点,计算机内部自动化操作等特点.doc
- 计算机网络基础与应用复习提纲,计算机网络及应用期末复习提纲
- anaconda 创建虚拟环境(自己版本)
- mysql易百_MySQL DATE类型(来自易百)
- elasticsearch--Master选举
- Scratch3.0 Blockly如何对Arduino编译下载
- 贪食蛇的C++实现(课程设计)
- ld.so.conf.d文件修改命令
热门文章
- 常见前端九十道面试题及答案-韩烨
- 挑战10的1,143,913次方种算法组合:这都不是事儿~~
- 曾鸣:互联网的本质是什么?| 内部干货
- 全球及中国铁矿石行业供求状况与投资决策建议报告2022版
- 中央财经大学c语言试题答案,中央财经大学C语言题
- JAVA毕业设计酒店管理系统设计与实现计算机源码+lw文档+系统+调试部署+数据库
- 那些值得借鉴的的国外创意404错误页面设计
- 三坐标检测之测量基准面的选择
- android摄像头拍照代码,Android调用摄像头拍照开发教程
- android 背景图缩放,android背景图按比例缩放方法