从年初开始进行此项工作,我和合作伙伴包亮付出了大量而艰辛的劳动。翻译中我们本着能够让所有人看明白、看懂的目的,反复修改高达五次。现基本翻译完毕,有出版意向,如果有意向欢迎联系,不甚感激!现在此文中展示其中的前言和第一章,欢迎各位博友对此翻译提出意见建议以及指导如何出版,在此谢过!

  • 原名:The Type Astronaut's Guide to Shapeless
  • 中文:类型编程晋级——shapeless类库使用指南
  • 作者:Dave Gurnell(戴夫·格内尔)
  • 翻译:魏守峰、包亮

前言

时间回到2011年初,我做了一些泛型编程(generic programming)的实验,最后这些实验形成了shapeless,我绝不会想到五年后它居然会成为一个被如此广泛使用的类库。非常感谢那些信任我并将shapeless用到项目中的人,这种信任对任何开源项目来说都是巨大的动力。同样感谢多年来对项目做出巨大贡献的人,截止写此书时共有81人,没有它们的帮助shapeless不可能这么有趣和有用。

尽管有这些积极因素,shapeless也经历了所有开源项目的通病:缺乏完善的、准确的、易懂的文档。尽管我知晓这一点,但还是没能抽出时间在这方面做些事情,责任全在我。Travis Brown在Stack Overflow的英勇的表现以及很多人的讨论和实践,从一定程度上弥补了这一缺陷(此处我要特别指出Sam Halliday的“Shapeless for Mortals”)。

但是Dave Gurnell改变了这一切:他为我们写了这本精彩的书,此书介绍了shapeless的最重要的应用:通过泛型编程实现类型类(type class)派生。为了写此书他搜集了大量的代码和文档,征求了我的意见,并将杂乱无章变的清晰、简明、实用。幸运的是他很好的实现了我的主张——shapeless是一个非常简单的类库,它体现了一系列简单的原则。 感谢Dave,你为我们做了一件伟大的事情。

Miles Sabin

shapeless作者

概要

此书是关于如何使用shapeless的指导,shapeless是基于Scala语言的泛型编程库。由于shapeless包含的内容过多,所以此书只是专注于一些非常有意思的使用案例并用它们描绘出一个可用的工具和编程模式的画面。

在本章开始处,先来介绍一下什么是泛型编程以及是什么原因使得shapeless让Scala开发者如此兴奋。

1.1 什么是泛型编程?

具体的类型是有帮助的,它向我们展示不同的代码片段如何能够组合到一起、帮助我们消除bug以及当我们编写代码的时候引导我们找到解决方案。

然而有时类型又太具体,有些情形下我们想探索不同类型之间的相似性来去除重复编码工作。例如,考虑以下两个类型:

case class Employee(name: String, number: Int, manager: Boolean)

case class IceCream(name: String, numCherries: Int, inCone: Boolean)

这两个模式类代表不同的数据种类,但是它们又非常相似,每种都包含三个类型相同的字段。假设我们要实现一个对它们都通用的操作,例如将它们的实例序列化到CSV文件中,尽管这两类数据相似,但是我们不得不写两个不同的方法来处理。分别如下:

def employeeCsv(e: Employee): List[String] =
List(e.name, e.number.toString, e.manager.toString) def iceCreamCsv(c: IceCream): List[String] =
List(c.name, c.numCherries.toString, c.inCone.toString)

泛型编程能够克服像上面这样由于不同数据类型带来的重复操作。shapeless很容易实现将具体的类型泛型化,这样就可以使用同一段代码来操作不同的类型。

比如,我们能用如下代码将employees和ice creams实例转换成同一类型。不用担心不理解以下代码,本书会在接下来的章节中详细介绍这些它们。

import shapeless._

val genericEmployee = Generic[Employee].to(Employee("Dave", 123, false))
// genericEmployee: shapeless.::[String,shapeless.::[Int,shapeless.::[
Boolean,shapeless.HNil]]] = Dave :: 123 :: false :: HNil val genericIceCream = Generic[IceCream].to(IceCream("Sundae", 1, false))
// genericIceCream: shapeless.::[String,shapeless.::[Int,shapeless.::[
Boolean,shapeless.HNil]]] = Sundae :: 1 :: false :: HNil

现在两个值变成了相同类型,都是异构的列表(简称HList),它包含一个字符串(String)、一个整型(Int)和一个布尔(Boolean)对象。接下来我们将研究HList类型和它在shapeless中所扮演的重要角色。目前为止关键问题在于我们已经解决了用同一个函数来序列化上面两种经过类型变换后的值。代码如下:

def genericCsv(gen: String :: Int :: Boolean :: HNil): List[String] =
List(gen(0), gen(1).toString, gen(2).toString) genericCsv(genericEmployee)
// res2: List[String] = List(Dave, 123, false) genericCsv(genericIceCream)
// res3: List[String] = List(Sundae, 1, false)

这个简单的例子展示了泛型编程的精髓。重新探究这些问题之后,我们用泛型代码块解决了问题并写出了适用于多种类型的精简代码。使用shapeless进行泛型编程可以消除大量的冗余代码,使Scala应用程序更容易读、写和维护。

听上去是不是很有诱惑?想想这些,让我们一起入坑吧!

1.2 关于此书

该书共分为两部分。

第一部分介绍类型类(type class)派生,这允许我们仅用一些泛型规则来为任何代数数据类型(algebraic data type,简称ADT)创建类型类实例。第一部分包含四章。

  • 第二章介绍泛型表示(generic representation),以及shapeless中名为Generic的类型类,Generic能够为任何一个模式类(case class)或密封特质(sealed trait)创建一个泛型解码器,将其转化为泛型。

  • 第三章用Generic派生自定义类型类实例,并创建一个类型类的例子用于将Scala中的数据编码为CSV格式,但是此技术可以扩展到许多情形。此外还介绍了shapeless中的Lazy类型,可以处理像列表(list)以及树(tree)等类型的递归数据。

  • 第四章介绍前几章涉及的理论和编程模式,特别是针对依赖类型、类型依赖函数以及类型级别编程,这些能使我们进入更高级的shapeless应用。

  • 第五章介绍LabelledGeneric,这是Generic的一个变体,它将字段名称和类型名称转换为其泛型表示的一部分。还介绍了一些理论知识:字面类型( literal)、单例类型(singleton)、幽灵类型(phantom)和类型标签(type tagging)。我们会创建一个在输出中保持字段和类型名称不变的JSON编码器,以此来演示LabelledGeneric。

第二部分介绍在shapeless.ops包中提供的“ops类型类”,它来源于一个处理泛型表示工具的扩展库。在接下来的三章中仅为大家介绍入门理论,而不是介绍每一个操作(op)的细节。

  • 第六章介绍ops类型类的通用设计方式并提供一个例子,实现将几个简单操作串联到一起组成一个强大的“模式类迁移”工具。

  • 第七章介绍多态函数(Poly)并展示在ops类型类中如何使用多态函数对“泛型表示”进行操作,这些操作包含map、flat Map以及fold。

  • 第八章介绍shapeless中用于在类型级别表示原始数字的Nat类型。介绍几个相关的ops类型类并用Nat建立我们自己的ScalaCheck(一个Scala测试框架)中的Arbitrary(随机数生成)类。

1.3 源码和例子

此书是开源的,你可以在Github中找到其markdown格式。本书会持续更新,所以请检查上述Github仓库以获取最新版本。

书中的大多数例子已经实现,你可以在此仓库中找到它们。细节请参考README文件。

我们推荐shapeless2.3.2版以及Typelevel Scala2.11.8+版或者Lightbend Scala2.11.9+/2.12.1+版。

1.4 致谢

感谢Miles Sabin、Richard Dallaway、Noel Welsh、Travis Brown和我们的Github仓库中的贡献者,他们为这本指导提供了不可估量的贡献。

特别感谢Sam Halliday,他的优秀的Shapeless for Mortals库为我们提供了最初的灵感和骨架。

最后,感谢Rob Norris和他的Tut库的跟随者,他们对我们的例子做了精心的验证,确保其编译无误。

《类型编程晋级——shapeless类库使用指南》前言及第一章翻译的更多相关文章

  1. 《深入理解Spark:核心思想与源码分析》(前言及第1章)

    自己牺牲了7个月的周末和下班空闲时间,通过研究Spark源码和原理,总结整理的<深入理解Spark:核心思想与源码分析>一书现在已经正式出版上市,目前亚马逊.京东.当当.天猫等网站均有销售 ...

  2. C++的XML编程经验――LIBXML2库使用指南[转]

    C++的XML编程经验――LIBXML2库使用指南 写这篇文章的原因有如下几点:1)C++标准库中没有操作XML的方法,用C++操作XML文件必须熟悉一种函数库,LIBXML2是其中一种很优秀的XML ...

  3. C++的XML编程经验――LIBXML2库使用指南

    C++的XML编程经验――LIBXML2库使用指南 写这篇文章的原因有如下几点:1)C++标准库中没有操作XML的方法,用C++操作XML文件必须熟悉一种函数库,LIBXML2是其中一种很优秀的XML ...

  4. 如何理解 TS 类型编程中的 extends 和 infer

    extends extends 在TS类型编程中用法(T extends U),表示 T 中的某些在 U 里面,比较难描述,用法如下: T extends U ? X : Y 分为两种情况理解更直观一 ...

  5. 《 .NET并发编程实战》一书中的节流为什么不翻译成限流

    有读者问,为什么< .NET并发编程实战>一书中的节流为什么不翻译成限流? 这个问题问得十分好!毕竟“限流”这个词名气很大,耳熟能详,知名度比“节流”大多了. 首先,节流的原词Thrott ...

  6. 《NodeJs开发指南》第五章微博开发实例的中文乱码问题

    在<NodeJs开发指南>第五章,按照书中的要求写好微博实例后,运行代码,发现中文显示出现乱码,原因是:views文件夹下的ejs文件的编码格式不是utf-8. 解决方法:以记事本方式打开 ...

  7. WCF分布式开发步步为赢(9):WCF服务实例激活类型编程与开发

    .Net Remoting的激活方式也有三种:SingleTon模式.SingleCall模式.客户端激活方式,WCF服务实例激活类型包括三种方式:单调服务(Call Service),会话服务(Se ...

  8. .NET本质论 用类型编程

    运行时的类型 类型本身并不是万能的.类型真正有意思的地方在于,程序员使用类型的实例,并让它们相互作用.类型的实例(instance)既可以是对象,也可以是值,这取决于类型如何定义的.基本数据类型(pr ...

  9. 进阶Java编程(5)基础类库

    Java基础类库 1,StringBuffer类 String类是在所有项目开发之中一定会使用到的一个功能类,并且这个类拥有如下的特点: ①每一个字符串的常量都属于一个String类的匿名对象,并且不 ...

随机推荐

  1. PHP 单态设计模式复习

    单态设计模式,也可以叫做单例设计模式, 就是一个类只能让它生成一个对象,避免重复的NEW,影响运行效率(每NEW一个对象都会在内存中开辟一块空间) 示例代码 <?php /* * 单态设计模式 ...

  2. java_web学习(3)XML基础

    XML 技术概述 XML是一种通用的数据交换格式.为实现计算机之间的文档交换而设计的文档内容编写规范,语法与HTML相似;XML的作用:统一信息的结构,实现不同系统之间的相互通信;目前许多系统的配置文 ...

  3. MySQL批量导出以某数字或字母开头的表

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://suifu.blog.51cto.com/9167728/1852178 情景:我 ...

  4. Struts2框架学习(二) Action

    Struts2框架学习(二) Action Struts2框架中的Action类是一个单独的javabean对象.不像Struts1中还要去继承HttpServlet,耦合度减小了. 1,流程 拦截器 ...

  5. 用mfix模拟流化床时压力边界条件和迭代步长需要注意的问题

    没想到今天模拟一个冷态流化床都出现这么多问题.需要通入三种气体组成的混合物,这时入口边界的压力BC_P_g不能为零,否则会报错,但是,需要注意的是,收敛效果对这个压力边界非常敏感,我随意给了个30,结 ...

  6. easyui datagrid分页参数获取

    $("#btnDataExport").click(function () { $.messager.show({ title: '导出提示', msg: '每次导出一页商户数据, ...

  7. 进度条(ProgressBar)的功能与用法

    进度条也是UI界面中一种非常实用的组件,通常用于向用户显示某个耗时操作完成的的百分比.进度条可以动态的显示进度,因此避免长时间的执行某个耗时的操作,让用户感觉程序失去了响应,从而更好的提高用户界面的友 ...

  8. MyBatis CRUD Java POJO操作

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC ...

  9. GCD简介

    什么是GCD 全称是Grand Central Dispatch,可译为"牛逼的中枢调度器" 纯C语言,提供了非常多强大的函数   GCD的优势 GCD是苹果公司为多核的并行运算提 ...

  10. DTLS 技术要点解析

    一.DTLS DTLS 是指 Datagram Transport Level Security,即数据报安全传输协议: 其提供了UDP 传输场景下的安全解决方案,能防止消息被窃听.篡改.身份冒充等问 ...