Scala: Types of a higher kind
One of the more powerful features Scala has is the ability to generically abstract across things that take type parameters. This feature is known as Higher Kinded Types (HKT).
This feature allows us to write a library that works with a much wider array of classes, whereas without the feature you are condemned to bespoke and error ridden code duplication for each class that may want the functionality.
Type constructors
Essentially what HKT gives us is the ability to generalize across type constructors – where a type constructor is anything that has a type parameter. For instance List[_]* is not a type, the underscore is a hole into which another type may be plugged, constructing a complete type. List[String] and List[Int] being examples of complete (or distinct) types.
Kinds
Now that we have a type constructor we can think of several different kinds of them, classified by how many type parameters they take. The simplest – like List[_] – that take a single param have the kind:
(* -> *)
This says: given one type, produce another. For instance, given String produce the type List[String].
Something that takes two parameters, say Map[_, _], or Function1[_, _] has the kind:
(* -> * -> *)
This says: given one type, then another, produce the final type. For instance given the key type Int and the value type String produce the type Map[Int, String].
Furthermore, you can have kinds that are themselves parameterized by higher kinded types. So, something could not only take a type, but take something that itself takes type parameters. An example would be the covariant functor: Functor[F[_]], it has the kind:
((* -> *) -> *)
This says: given a simple higher kinded type, produce the final type. For instance given a type constructor like List produce the final type Functor[List].
Utility
Say we have some standard pattern for our data-structures where we want to be able to consistently apply an operation of the same shape. Functors are a nice example, the covariant functor allows us to take a box holding things of type A, and a function of A => B and get back a box holding things of type B.
In Java, there is no way to specify that these things share a common interface, or that we simply want transformable boxes. We need to either make this static eg. Guava’s Listsand Iterables, or bespoke on the interface, eg: fugue’s Option or atlassian-util-concurrent’s Promise. There is simply no way to unify these methods on either some super interface or to specify that you have – or require – a “mappable/transformable” box.
With HKT I can represent the covariant functor described above as:
[cc lang=’scala’ ]
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
// implement for java’s List
// note that the presence of mutation in the Java collections
// breaks the Functor laws
import java.util.{ List => JList }
implicit object JavaListFunctor extends Functor[JList] {
import collection.JavaConverters._
def map[A, B](fa: JList[A])(f: A => B): JList[B] =
(for (a B): Box2[B] =
Box2(f(b.a1), f(b.a2))
}
// and use it**
def describe[A, F[_]: Functor](fa: F[A]) =
implicitly[Functor[F]].map(fa)(a => a.toString)
case class Holder(i: Int)
val jlist: JList[Holder] = {
val l = new java.util.ArrayList[Holder]()
l add Holder(1); l add Holder(2); l add Holder(3)
l
}
val list = describe(jlist) // list: java.util.List[String] = [Holder(1), Holder(2), Holder(3)]
val box2 = describe(Box2(Holder(4), Holder(5)) // box: Box2[String] = Box2(Holder(4),Holder(5))
[/cc]
So, we have a describe function that works for any type that we can map over!
We could also use this with a traditional subtyping approach to have our boxes implement the map method directly with the appropriate signature. This is a little more convoluted, but still possible:
[cc lang=’scala’]
/**
* note we need a recursive definition of F as a subtype of Functor
* because we need to refer to it in the return type of map(…)
*/
trait Functor[A, F[_] B): F[B]
}
case class Box[A](a: A) extends Functor[A, Box] {
def map[B](f: A => B) =
Box(f(a))
}
def describe[A, F[A] a.toString)
val box = describe(Box(Holder(6))) // box: Box[String] = Box(Holder(6))
[/cc]
As a bonus, this last example quite nicely shows how subtype polymorphism is strictly less powerful and also more complicated (both syntactically and semantically) than ad-hoc polymorphism via type-classes.
Postscript
These techniques can lead to some very general and powerful libraries, such as scalaz, spire and shapeless. These libraries may take some getting used to, and as many of these generalizations are inspired by the mother of all generalizations – mathematics – they have names that need learning (like Monad).
However, the techniques are useful without needing to use scalaz. HKT is important for creating type-classes, and creating your own type-classes to encapsulate things like JSON encoding may be of value to your project. There are many ways this can be used within Scala.
If you’re interested in reading more, here’s the original paper for Scala. Among other things, it contains the following very useful graphic:
Also note that the Scala 2.11 REPL is getting a :kind command although its output is a little more convoluted due to the presence of variance annotations on type parameters.
* Strictly speaking, in Scala List[_] is actually an existential type. For the purposes of this post I am using the [_] notation to show the existence of type parameters. Thanks to Stephen Compall for pointing this out.
** An alternate syntax for a context-bound is an explicit implicit block:
[cc lang=’scala’]
def describe2[A, F[_]](fa: F[A])(implicit functor: Functor[F]) =
functor.map(fa) { _.toString }
[/cc]
https://www.atlassian.com/blog/archives/scala-types-of-a-higher-kind
Scala: Types of a higher kind的更多相关文章
- Scala Types 2
存在类型 形式: forSome { type ... } 或 forSome { val ... } 主要为了兼容 Java 的通配符 示例 Array[_] // 等价于 Array[T] for ...
- Scala Types 1
在 Scala 中所有值都有一种对应的类型 单例类型 形式:value.type,返回类型 value / null 场景1:链式API调用时的类型指定 class Super { def m1(t: ...
- Beginning Scala study note(8) Scala Type System
1. Unified Type System Scala has a unified type system, enclosed by the type Any at the top of the h ...
- scala速成记录1
选择 Learning Scala这本书,两百多页,足够薄. 安装 http://www.scala-lang.org/ 下载Binary的版本.bin里边有所有操作系统下运行的可以运行的交互式s ...
- Scala 中的函数式编程基础(二)
主要来自 Scala 语言发明人 Martin Odersky 教授的 Coursera 课程 <Functional Programming Principles in Scala>. ...
- geotrellis使用(十九)spray-json框架介绍
Geotrellis系列文章链接地址http://www.cnblogs.com/shoufengwei/p/5619419.html 目录 前言 spray-json简介 spray-json使用 ...
- 论文笔记之:Visual Tracking with Fully Convolutional Networks
论文笔记之:Visual Tracking with Fully Convolutional Networks ICCV 2015 CUHK 本文利用 FCN 来做跟踪问题,但开篇就提到并非将其看做 ...
- Akka(33): Http:Marshalling,to Json
Akka-http是一项系统集成工具.这主要依赖系统之间的数据交换功能.因为程序内数据表达形式与网上传输的数据格式是不相同的,所以需要对程序高级结构化的数据进行转换(marshalling or se ...
- 【原创】大叔问题定位分享(11)Spark中对大表子查询加limit为什么会报Broadcast超时错误
当两个表需要join时,如果一个是大表,一个是小表,正常的map-reduce流程需要shuffle,这会导致大表数据在节点间网络传输,常见的优化方式是将小表读到内存中并广播到大表处理,避免shuff ...
随机推荐
- hdu_1863_畅通工程_201403122000
畅通工程 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- [转]十五天精通WCF——第十二天 说说wcf中的那几种序列化
我们都知道wcf是由信道栈组成的,在我们传输的参数走到传输信道层之前,先需要经过序列化的过程,也就是将参数序列化为message,这篇 我们就来说说这里的序列化,蛮有意思的,可能初学者也明白,在wcf ...
- Openfire:访问Servlet时绕开Openfire的身份验证
假设有如下的场景,当我们开发一个允许Servlet访问的OF插件时,如果不需要身份验证的话,或者有其它的安全机制的话,我们会不希望每次都做一次OF的身份验证,而是能够直接访问Servlet.绕开身份验 ...
- HDU 1561&HDU 3449 一类简单依赖背包问题
HDU 1561.这道是树形DP了,所谓依赖背包,就是选A前必须选B,这样的问题.1561很明显是这样的题了.把0点当成ROOT就好,然后选子节点前必须先选根,所以初始化数组每一行为该根点的值.由于多 ...
- android 用java代码设置布局、视图View的宽度/高度或自适应
在achat项目中,对话内容的长宽设置为自适应.可是假设文本内容太多,则宽度几乎相同布满,若自己说的和对方说的都非常多内容.则满屏都是文字.则不easy分辨出是来自别人说的还是自己说的.那么须要对本身 ...
- 初识ASP.NET---点滴的积累---ASP.NET学习小结
差点儿相同十多天前学习完了北大青鸟的学习视频,没想到没几天的时间就看完了XML视频和牛腩的Javascript视频.学习完了也该总结总结.理理自己的思路.消化一下自己学习到的东西. 视频中的理论知识并 ...
- C++ Web 编程(菜鸟教程)
C++ Web 编程(菜鸟教程) C++ Web 编程 什么是 CGI? 公共网关接口(CGI),是一套标准,定义了信息是如何在 Web 服务器和客户端脚本之间进行交换的. CGI 规范目前是由 NC ...
- iOS开发之KVC全解
一 KVC的基本概念 1.KVC是Key Value Coding的缩写,意思是键值编码. 在iOS中,提供了一种方法通过使用属性的名称(也就是Key)来间接访问对象属性的方法,这个方法可以不通过g ...
- 第7章 Android中访问网络资源
http://developer.android.com/index.html->https://developer.android.com/index.html https://develop ...
- PCB MongoDb安装与Windows服务安装
工程MI流程指示做成Web网页形式,采用MVC框架制作,数据传输用Web API方式, 最终此网页会挂到公司各系统中访问,为了提高访问并发量,并将工程数据统一结构化管理, 采用No SQL Mongo ...