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. In comp
, I've specifically taken a parameter constructed with Test
, which gives the Ord
constraint allowing me to use <
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.
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?
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:
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. 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)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.