Haskell 为什么可以';类型族上的模式匹配吗?
考虑以下代码:Haskell 为什么可以';类型族上的模式匹配吗?,haskell,types,Haskell,Types,考虑以下代码: {-# LANGUAGE TypeFamilies #-} data Twothings a b = Twothings a b type family Leftthing a where Leftthing (Twothings a b) = Leftthing a Leftthing a = a leftthing :: a -> Leftthing a leftthing (Twothings a b) = leftthing a leftthing b
{-# LANGUAGE TypeFamilies #-}
data Twothings a b = Twothings a b
type family Leftthing a where
Leftthing (Twothings a b) = Leftthing a
Leftthing a = a
leftthing :: a -> Leftthing a
leftthing (Twothings a b) = leftthing a
leftthing b = b
它未编译,出现以下错误:
Couldn't match expected type ‘a’
with actual type ‘Twothings a0 t0’
‘a’ is a rigid type variable bound by
the type signature for:
leftthing :: forall a. a -> Leftthing a
它抱怨行leftthing(twoothingab)=leftthinga
。如果我理解正确,它无法将类型签名中的类型变量a
与构造函数的类型twoothings
统一起来。好吧,这似乎有道理。但是,我怎样才能在类型签名中定义具有类型族的函数呢
leftthing :: a -> Leftthing a
您的意思是,leftthing
的调用者可以选择a
是什么
当你写的时候
leftthing (Twothings a b) = leftthing a
您假定他们选择了twoothings
类型,但情况并非如此,因此您的程序被拒绝
您可能认为您正在测试他们是否选择了twoothings
类型,但没有!类型信息在运行时之前被擦除,因此无法进行此类测试
您可以尝试还原必要的运行时信息。首先,让我修复Leftthing
和Leftthing
之间的不一致性
type family Leftthing a where
Leftthing (Twothings a b) = Leftthing{-you forgot the recursion!-} a
Leftthing a = a
现在我们可以将证人的GADT定义为twoothing
ness
data IsItTwothings :: * -> * where
YesItIs :: IsItTwothings a -> IsItTwothings (Twothings a b)
NoItIsn't :: Leftthing a ~ a => IsItTwothings a
-- ^^^^^^^^^^^^^^^ this constraint will hold for any type
-- which is *definitely not* a Twothings type
然后我们可以传证人作为论点:
leftthing :: IsItTwothings a -> a -> Leftthing a
leftthing (YesItIs r) (Twothings a b) = leftthing r a
leftthing NoItIsn't b = b
实际上,见证是类型根处左嵌套的twoothings
es的数量的一元编码。这些信息足以在运行时确定要执行的正确解包量
> leftthing (YesItIs (YesItIs NoItIsn't)) (Twothings (Twothings True 11) (Twothings "strange" [42]))
True
总之,您无法通过对值进行模式匹配来找到类型。相反,您需要知道进行模式匹配的类型(因为类型决定内存布局,并且没有运行时类型标记)。您不能直接在类型上进行模式匹配(因为它们只是不需要进行匹配)。您可以构造作为类型结构的运行时证据的数据类型,并在这些数据类型上进行匹配
也许有一天,如果你给它类型,你的程序会工作
leftthing :: pi a. a -> Leftthing a
其中,
pi
是相关量词,表示隐藏类型参数不会被删除,而是在运行时传递和匹配。那一天还没有到来,但我想它会到来。你想解决的问题是什么?我可以举出使用类型族的例子,但我更愿意回答一个更具体的问题。感谢您发现我在类型族声明中的错误!(现已修复)