Type family快速教程

最近没有什么填的上的坑啊。于是为了Github连击不断,只好在这水一水理论了。

PS. 发现Codewars这个站很有意思,有兴趣的可以来互fo:http://www.codewars.com/users/kokonotsu

好的言归正传,今天来说说type family。

是什么

type family是GHC用来支持ad-hoc数据类型重载的扩展,相当于data type的type class。两种风味data familytype family,两种定义形式stand alone的和class associated的。写出来是这个样子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{-# LANGUAGE TypeFamilies #-}

-- Standalone data family
data family XList a
data instance XList Char = XNil | XCons Char (XList a)
data instance XList () = XList Int

-- Standalone type family
type family GMap k v
type instance GMap Int Int = Map Int Int
type instance GMap () a = a

-- Associated form
class FamilyClass m where
data Foo m :: * -> *
type Bar
foobar :: Foo -> Bar

instance FamilyClass Int where

data Foo Int v = Foo (Map Int v)
type Bar = [Int]
foobar = ...

大概就是这样,即构造一个抽象类型,依照不同的类型有不同的实现,但依然有一个统一的接口。按照维基的说法,可以把type family理解成一个类型层面的函数部分应用,即高阶kind。

为什么

这玩意有什么用?某种意义上来说,它可以取代Functional Dependencies。

1
2
3
4
5
6
7
8
{-# LANGUAGE FunctionalDependencies, TypeFamilies #-}

class FuncClass a b | b -> a where

foo :: a -> b -> a

class FamClass a where

data Elem a :: * -> * -> *
bar :: a -> Elem a -> a

这样。可以避免Multi Parameter Class的出现。同时可以根据具体类型实现不同的优化,颇有一番Dependent Type的味道。

还有什么?

基本用法就是这样了。需要注意的是type family的类型变量是限定在class范围内的。就上面的例子而言,data Elem a中的a必须要与class FamClass a中的a一致。此外还有GHC类型推导的一些坑,可以参照Haskell Wiki

以上。是不是速度太快了啊(逃