简体   繁体   English

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

[英]Get constraint in GADT-style declaration without specifically using constructor?

Consider the following: 考虑以下:

{-# 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

The constructor Test is declared with an Ord constraint. 构造函数TestOrd约束声明。 In comp , I've specifically taken a parameter constructed with Test , which gives the Ord constraint allowing me to use < comp ,我专门采用了Test构造的参数,该参数给出了Ord约束,使我可以使用<

Now, suppose I wanted to write: 现在,假设我想写:

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

Using the projection functions to get the first and second element. 使用投影函数获取第一个和第二个元素。 This is not okay because my parameter x was not (necessarily) constructed with Test , so there is no Ord constraint. 这是不对的,因为我的参数x不是(必需)用Test构造的,所以没有Ord约束。

So, for my question, is there a way to take the parameter as just x but still somehow have the Ord constraint from the Test constructor, without having to "unpack" or pattern match on the Test constructor or add the constraint to my function? 所以,我的问题,是有办法把参数作为刚刚x ,但仍不知何故有Ord从约束Test的构造,而不必“解压”或模式匹配的Test构造函数或约束添加到我的功能?

As for why I would want this, I have a data type with a constructor taking many values, one of which I only need in this particular function, so unpacking it makes my function unnecessarily verbose: 至于为什么要这样,我有一个带有许多值的构造函数的数据类型,其中一个仅在此特定函数中需要,所以解压缩它会使我的函数不必要地冗长:

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

As opposed to 相对于

myFunction t = ... (need t)

You can define a function which extracts all of the constraints from the constructor: 您可以定义一个函数,该函数从构造函数中提取所有约束:

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

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

You can then write 然后你可以写

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

but note that the implementation of openTest is completely trivial - and it is less typing to just inline the pattern matching: 但是请注意, openTest的实现是非常简单的-仅内联模式匹配就不需要键入代码了:

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

Note also this (ie the Test{} syntax) will work with any constructor, even if it is not a record constructor. 还请注意,此方法(即Test{}语法)将适用于任何构造函数,即使它不是记录构造函数也是如此。 Your actual function can simply be expressed as 您的实际功能可以简单地表示为

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

or equivalently 或同等

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

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

Finally, you can also define a function to extract a specific field as well as the constraints which apply to this field, which can be very useful for large constructors with many constraints: 最后,您还可以定义一个函数以提取特定字段以及适用于该字段的约束,这对于具有许多约束的大型构造函数可能非常有用:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM