[英]Get constraint in GADT-style declaration without specifically using constructor?
考慮以下:
{-# 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
構造函數Test
用Ord
約束聲明。 在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)
您可以定義一個函數,該函數從構造函數中提取所有約束:
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)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.