2013-08-04 22 views
4

是否有可能對Haskell中的匹配元組進行模式化,但不知道元組的維度?我想創建馬赫對任何元組,其中第一個元素是A,喜歡的功能:Haskell中基於位置的元組模式匹配

data A = A Int 
test [email protected](A a,..) = a 

我知道有Data.Tuple.Select模塊,我可以這樣使用它:

test args = case sel1 args of 
    A a -> a 
    ... 

不過是這是做這件事的唯一方法還是讓Haskell得到了一些默認機制來匹配任何維度元組?

回答

7

您可以使用ViewPatterns擴展模式與作用於自變量的函數的結果:

{-# LANGUAGE ViewPatterns #-} 

data A = A Int 
test (fst -> A a) = a 

你可以使用鏡頭投射出任意字段:

{-# LANGUAGE ViewPatterns #-} 

import Control.Lens 
import Control.Arrow ((&&&)) 

data A = A Int 
test (fields _1 _3 -> (A x, A y)) = x + y 

fields f1 f2 = (^.f1) &&& (^.f2) 

-- > test (A 1, A 2, A 3) 
-- > 4 
4

如果你不你不想使用類型類,你也可以使用嵌套元組。因此,不是有一個(A, B, C, D)類型的元組,而是有一個(A, (B, (C, D)))的元組。

然後,您可以輕鬆匹配反對但深度嵌套的元組的第一個元素,像這樣:

test :: (A, b) -> Int 
test (A a, _) = a 
+0

謝謝你的解決方案!我會用它。它不會回答我的問題(因爲它使用嵌套元組),但它非常非常酷。 –

2

任何解決方案將不得不元組某種程度上概括了作爲默認他們只是不相交的類型。最常見的解決方案將使用類型類來索引「具有第一個元素」的類型的想法,例如Control.LensData.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 ... 

儘管對於這一切的神奇它仍然通過類型類實現了這項工作。