任何解決方案將不得不元組某種程度上概括了作爲默認他們只是不相交的類型。最常見的解決方案將使用類型類來索引「具有第一個元素」的類型的想法,例如Control.Lens
或Data.Tuple.Select
所做的。
class Sel1 a b | a -> b where sel1 :: a -> b
instance Sel1 (a1,a2) a1 where sel1 (x,_) = x
instance Sel1 (a1,a2,a3) a1 where sel1 (x,_,_) = x
instance Sel1 (a1,a2,a3,a4) a1 where sel1 (x,_,_,_) = x
...
或
instance Field1 (Identity a) (Identity b) a b where
_1 f (Identity a) = Identity <$> indexed f (0 :: Int) a
instance Field1 (a,b) (a',b) a a' where
_1 k ~(a,b) = indexed k (0 :: Int) a <&> \a' -> (a',b)
instance Field1 (a,b,c) (a',b,c) a a' where
_1 k ~(a,b,c) = indexed k (0 :: Int) a <&> \a' -> (a',b,c)
instance Field1 (a,b,c,d) (a',b,c,d) a a' where
_1 k ~(a,b,c,d) = indexed k (0 :: Int) a <&> \a' -> (a',b,c,d)
...
在這兩種情況下,考慮你的函數的類型,就必須有一種方式來指定你的第一個參數是一個「之類的話與第一元素」 。
test :: (Sel1 s A) => s -> ...
test :: (Field1 s t A b) => s -> ...
你也可以去的fixed-vector
路線,並考慮元組短同質載體。你失去了作用於異構載體的能力,但你獲得整潔的類型(但醜陋的值),如
test :: (Vector v A, Index N1 (Dim v)) => v A -> ...
test v = let (A a) = index (1,2) (undefined :: Z) in ...
儘管對於這一切的神奇它仍然通過類型類實現了這項工作。
謝謝你的解決方案!我會用它。它不會回答我的問題(因爲它使用嵌套元組),但它非常非常酷。 –