由于我不完全理解,此幻灯片显示了实现X-Real-IP
的两种方式:通过类型类或类型族。
我熟悉类型类,因此实现了Eq
:
MyEq
但是,当我尝试定义class MyEq a where
eq :: a -> a -> Bool
版本时,它无法编译:
type family
由于:
data Defined = Yes | No
type family IsEq (a :: *) :: Defined
请说明如何实施TypeEq.hs:30:30: error:
• Type constructor ‘Defined’ cannot be used here
(Perhaps you intended to use DataKinds)
• In the kind ‘Defined’
类型的type family
版本。
另外,请展示这样一个Eq
实例的实现(如果这个甚至是正确的词)。
答案 0 :(得分:6)
这有点整洁,很高兴偶然发现了这一点。对于感兴趣的人,here是幻灯片,here是纸。这是需要一些语言扩展的常见情况。
{-# LANGUAGE DataKinds, TypeFamilies, TypeOperators, ConstraintKinds #-}
data Defined = Yes | No
type family IsEq (a :: *) :: Defined
type Eq a = IsEq a ~ Yes
然后,"实施"这是像
这样的例子type instance IsEq () = Yes -- '()' is an instance of 'Eq'
type instance IsEq Int = Yes -- 'Int' is an instance of 'Eq'
type instance IsEq [a] = IsEq a -- '[a]' is an instance of 'Eq' is 'a' is
你可以尝试"他们出现在GHCi:
ghci> :kind! IsEq [Int]
IsEq [Int] :: Defined
= Yes
但纸张和幻灯片并没有真正过分担心实际提供相等功能。 (它提到将其存储在Yes
的字段中)。那么,如果它还没有准备好提供类方法,为什么这很有趣呢?因为
No
构造函数中编码为字段)答案 1 :(得分:1)
尝试添加DataKinds
作为语言扩展名(例如,在"语言" pragma下的文件顶部),如错误消息所示。
我还没看过这个话题,但是iiuc,Defined
只是Bool
,其中Yes
是True
。因此,如果你启用DataKinds,你可以使用IsEq a ~ 'True
(和True之前的撇号意味着"这是一种类型")。
一些背景知识:此扩展程序的作用是"引发"任何代数数据类型的每个值(即声明为data
,但不是GADTs
,iiuc)为其自己的类型;然后将每种类型提升到它自己的类型中("种类"在Haskell中是"类型类型"),即不是"种类*" (发音为" kind star"),这是运行时存在的普通Haskell值。
顺便说一句:
[Bool] :: *
表示"留置权列表是一种类型"。并且[] :: * -> *
表示列表的类型构造函数具有类型"类型以键入",即"一旦您为List提供单个类型,您将返回类型"。