在类和实例声明中键入关键字

时间:2012-08-03 05:01:51

标签: haskell

我正在查看Data.Has的源代码,并试图弄清楚它是如何工作的。我相信以下代码旨在允许某人“加入”两个值,例如a :: Ab :: B到具有ab功能的新值

我特别不明白type在类和实例声明中的含义。

此外,我不知道下面的~符号是什么意思。

有人可以从Data.Has.TypeList解释以下代码吗?

-- | Provides type-list functionality

module Data.Has.TypeList where

import Control.Applicative
import Data.Monoid (Monoid (..))
import Test.QuickCheck (Arbitrary (..), CoArbitrary (..))
import Data.Typeable
import Data.Data
-- | Cons a type onto type-list.
data a ::: b = a ::: b deriving (Show,Eq,Ord,Read,Bounded,Typeable,Data)

-- | The empty type-list.
data TyNil = TyNil deriving (Read,Typeable,Data)

-- | Appends a type-list and another.
class Append a b where
    type a :++: b
    (.++.) :: a -> b -> a :++: b
infixr 5 :++:

-- Implementation of Append

instance Append TyNil b where
    type TyNil :++: b = b
    _ .++. b = b

instance (Append y b) => Append (x ::: y) b where
    type (x ::: y) :++: b = x ::: (y :++: b)
    ~(x ::: y) .++. b = x ::: (y .++. b)

1 个答案:

答案 0 :(得分:8)

类型类和实例声明中的

type语法是TypeFamilies扩展的一部分。类型族可以被认为是从类型到类型的函数。 Haskell wiki中有关于类型和数据系列的详细解释(参见链接)。

应用于类型类,类型族成为关联类型。在这方面,它们非常接近FunctionalDependencies,也就是说,它们允许毫无根据的实例解析。需要对此进行充分解释in the GHC manual

示例中的类型定义非常简单。 :::是2元组的另一个名称(一对值),TyNil与单位类型()同构。

我将尝试阅读类和实例声明,以便明确它们的含义。

class Append a b where
    type a :++: b
    (.++.) :: a -> b -> a :++: b
infixr 5 :++:
  

声明具有关联类型Append a b的多参数类型类a :++: b和一个方法函数(.++.),它采用类型ab的值并生成一个值输入a :++: b。我们还将(.++.)设置为与优先级5正确关联。

instance Append TyNil b where
    type TyNil :++: b = b
    _ .++. b = b
  

使用固定的第一个参数(Append a b)和任意第二个参数(TyNil)声明b的实例,其中关联的类型为a :++: b(在本例中为{声明{1}})等于TyNil :++: b。 (我不会描述采用什么方法,但相当清楚)。

b
  

声明instance (Append y b) => Append (x ::: y) b where type (x ::: y) :++: b = x ::: (y :++: b) ~(x ::: y) .++. b = x ::: (y .++. b) 的实例,Append a b形式的第一个参数用于任意x ::: yx以及任意第二个参数y,因为已经存在声明了b的实例。关联类型Append y b(此处a :++: b,显然)声明等于(x ::: y) :++: b。方法定义在这里也很明确:它接受一对值和另一个值,并构造另一对,其中第一个元素与第一个参数相同,第二个元素是第一个参数的第二个元素,第二个参数与{{1 }} 方法。由于x ::: (y :++: b)约束

,我们可以使用.++.

这些是类声明和实例声明中.++.方法的类型签名:

Append y b

请注意,在每个实例中,非常抽象的(.++.)转换为更具体的类型。在第一种情况下它是(.++.) :: a -> b -> a :++: b (.++.) :: TyNil -> b -> b (.++.) :: Append y b => x ::: y -> b -> x ::: (y :++: b) ,而在a :++: b方面则更为复杂b

需要这种关联类型的声明来告诉类型系统某些类型(在这种情况下为x ::: (y :++: b))由:++:和{{唯一确定 1}}单独。也就是说,如果typechecker知道某些表达式a :++: ba类型等于ba,并且:

  1. 存在约束b;
  2. 有一个类型类实例Int,其中声明了相关类型,例如Double
  3. 然后,类型检查员会知道,如果他遇到类型Append a b,它就会知道实际上这种类型是Append Int Double

    至于type Int :++: Double = String,它被称为'懒模式匹配'。这是非常清楚地解释here

    随意询问是否还有不清楚的事情。