4

Haskellでタプルをパターンマッチすることは可能ですが、タプルの次元を知らなくてもできますか? 次のように、最初の要素が である任意のタプルに対して一致する関数を作成したいと思いますA

data A = A Int
test args@(A a,..) = a

モジュールがあることを知っておりData.Tuple.Select、次のように使用できます。

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

しかし、これがこれを行う唯一の方法ですか、それとも Haskell には任意の次元のタプルと照合するためのデフォルトのメカニズムがありますか?

4

3 に答える 3

4

型クラスを使用したくない場合は、ネストされたタプルを使用することもできます。したがって、 type のタプルを使用する代わりに、 の(A, B, C, D)タプルを使用し(A, (B, (C, D)))ます。

次に、次のように、深くネストされたタプルの最初の要素と簡単に一致させることができます。

test :: (A, b) -> Int
test (A a, _) = a
于 2013-08-04T22:06:02.033 に答える
2

デフォルトではタプルは単純にばらばらの型であるため、どのような解決策でもタプルを一般化する必要があります。最も一般的な解決策は、型クラスを使用して、「最初の要素を持つ」型のアイデア (whatControl.Lensやdos など) にインデックスを付けること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 ...

ただし、そのすべての魔法にもかかわらず、型クラスを介してこの作業を実現しています。

于 2013-08-04T23:02:05.183 に答える