在没有专门使用构造函数的情况下获取GADT样式声明中的约束?

时间:2016-07-29 06:05:02

标签: haskell type-constraints gadt

请考虑以下事项:

{-# LANGUAGE GADTs, GADTSyntax #-}

data Test a where
    Test :: Ord a => { first :: a, second :: a } -> Test a

comp :: Test a -> Bool
comp (Test fst snd) = fst < snd

构造函数TestOrd约束声明。在comp中,我专门采用了Test构造的参数,该参数提供Ord约束,允许我使用<

现在,假设我想写:

comp' :: Test a -> Bool
comp' x = (first x) < (second x)

使用投影函数获取第一个和第二个元素。这没关系,因为我的参数x没有(必然)用Test构建,因此没有Ord约束。

因此,对于我的问题,有没有办法将参数仅作为x,但仍然以某种方式从Ord构造函数获得Test约束,而不必“解包”或Test构造函数上的模式匹配或将约束添加到我的函数?

至于为什么我想要这个,我有一个带有构造函数的数据类型,它带有很多值,其中一个我只需要在这个特定的函数中,所以解压缩它会使我的函数不必要地冗长:

myFunction :: Thing -> ...
myFunction (Thing _ _ _ _ need _ _) ...

相反
myFunction t = ... (need t)

1 个答案:

答案 0 :(得分:1)

您可以定义一个从构造函数中提取所有约束的函数:

data Test a where
    Test :: Ord a => { first :: a, second :: a } -> Test a

openTest :: Test a -> (Ord a => r) -> r 
openTest Test{} x = x 

然后你可以写

comp :: Test a -> Bool
comp x = openTest x $ first x < second x 

但请注意openTest的实现完全是微不足道的 - 只是内联模式匹配的输入更少:

comp' :: Test a -> Bool
comp' x@Test{} = first x < second x 

另请注意,这(即Test{}语法)将适用于任何构造函数,即使它不是记录构造函数。您的实际功能可以简单地表示为

myFunction t@Thing{} = ... (need t) ...

或等效

openThing :: Thing a -> (ThingConstraints a => r) -> r 
openThing Thing{} x = x 

myFunction t = ... (openThing $ need t) ...

最后,您还可以定义一个函数来提取特定字段以及适用于此字段的约束,这对于具有许多约束的大型构造函数非常有用:

first' :: Test a -> (Ord a => a -> r) -> r 
first' t@Test{} x = x (first t)