我正在查看源代码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)
Run Code Online (Sandbox Code Playgroud)
type类型类和实例声明中的语法是TypeFamilies扩展的一部分.类型族可以被认为是从类型到类型的函数.Haskell wiki中有关于类型和数据系列的详细解释(参见链接).
应用于类型类,类型族成为关联类型.在这方面,他们非常接近FunctionalDependencies,也就是说,他们允许毫无根据的实例解析.在GHC手册中充分解释了对此的需求.
示例中的类型定义非常简单.:::是2元组的另一个名称(一对值),与TyNil单元类型同构().
我将尝试阅读类和实例声明,以便明确它们的含义.
class Append a b where
type a :++: b
(.++.) :: a -> b -> a :++: b
infixr 5 :++:
Run Code Online (Sandbox Code Playgroud)
声明多参数类型类
Append a b与相关联的类型a :++: b和一个方法的功能(.++.)这需要的类型的值a和b并产生类型的值a :++: b.我们还设置(.++.)为与优先级5正确关联.
instance Append TyNil b where
type TyNil :++: b = b
_ .++. b = b
Run Code Online (Sandbox Code Playgroud)
声明
Append a b具有固定的第一个参数(TyNil)和任意第二个参数(b)的实例,其中关联的类型a :++: b(在这种情况下它是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)
Run Code Online (Sandbox Code Playgroud)
声明的实例
Append a b与表单中第一个参数x ::: y为任意的x和y和任意的第二个参数b给出的,已经有实例Append y b声明.关联类型a :++: b(此处(x ::: y) :++: b,显然)声明等于x ::: (y :++: b).方法定义在这里也很清楚:它接受一对值和另一个值,并构造另一对,其中第一个元素与第一个参数相同,第二个元素是第一个参数的第二个元素,第二个参数与.++.方法相结合.我们被允许使用.++.因为Append y b约束
这些是(.++.)类声明和实例声明中方法的类型签名:
(.++.) :: a -> b -> a :++: b
(.++.) :: TyNil -> b -> b
(.++.) :: Append y b => x ::: y -> b -> x ::: (y :++: b)
Run Code Online (Sandbox Code Playgroud)
请注意,在每个实例中,非常抽象a :++: b转换为更具体的类型.它b在第一种情况下很简单,而且更复杂x ::: (y :++: b),本身就是用它来写的:++:.
需要相关联的类型的,例如声明告诉型系统,该系统有一些类型(a :++: b在这种情况下),其唯一地确定通过a和b单独.也就是说,如果typechecker知道某些表达式a和b类型等于,比如,Int和Double,和:
Append a b;Append Int Double,声明了相关的类型,比如,as type Int :++: Double = String,那么类型检查员会知道,如果他遇到类型,a :++: b它会知道实际上这种类型是String.
至于~它被称为'懒模式匹配'.这里有很清楚的解释.
随意询问是否仍然不清楚.