我正在查看Data.Has
的源代码,并试图弄清楚它是如何工作的。我相信以下代码旨在允许某人“加入”两个值,例如a :: A
和b :: B
到具有a
和b
功能的新值
我特别不明白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)
答案 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
和一个方法函数(.++.)
,它采用类型a
和b
的值并生成一个值输入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 ::: y
和x
以及任意第二个参数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 :++: b
和a
类型等于b
和a
,并且:
b
; Int
,其中声明了相关类型,例如Double
,然后,类型检查员会知道,如果他遇到类型Append a b
,它就会知道实际上这种类型是Append Int Double
。
至于type Int :++: Double = String
,它被称为'懒模式匹配'。这是非常清楚地解释here。
随意询问是否还有不清楚的事情。