Haskell Position Based Template Match

Is it possible to combine tuples in Haskell, but not knowing the dimensions of the tuple? I want to create a function that works against any tuple whose first element is A , for example:

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

I know that there is a Data.Tuple.Select module, and I can use it as follows:

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

But is this the only way to do this, or has Haskell got some default mechanisms to fit any size tuple?

+4
source share
3 answers

You can use the ViewPatterns extension to match the pattern with the result of the function applied to the argument:

 {-# LANGUAGE ViewPatterns #-} data A = A Int test (fst -> A a) = a 

You can use lenses to project arbitrary fields:

 {-# 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 
+7
source

If you do not want to use type classes, you can also use nested tuples. Therefore, instead of a tuple of type (A, B, C, D) , you have a tuple (A, (B, (C, D))) .

Then you can easily map the first element of any deeply nested tuple, for example:

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

Any solution should somehow generalize the tuples, because by default they are just disjoint types. The most common solution would be to use typeclasses to index the idea of ​​types that have a "first element", such as Control.Lens or Data.Tuple.Select .

 class Sel1 ab | 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 ... 

or

 instance Field1 (Identity a) (Identity b) ab where _1 f (Identity a) = Identity <$> indexed f (0 :: Int) a instance Field1 (a,b) (a',b) aa' where _1 k ~(a,b) = indexed k (0 :: Int) a <&> \a' -> (a',b) instance Field1 (a,b,c) (a',b,c) aa' 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) aa' where _1 k ~(a,b,c,d) = indexed k (0 :: Int) a <&> \a' -> (a',b,c,d) ... 

In both cases, consider the type of your function, it will need to indicate a way for your first argument to be "the kind of thing with the first element."

 test :: (Sel1 s A) => s -> ... test :: (Field1 st A b) => s -> ... 

You can also follow the fixed-vector route and consider tuples as short homogeneous vectors. You lose the ability to act on heterogeneous vectors, but you get neat types (but ugly values) like

 test :: (Vector v A, Index N1 (Dim v)) => v A -> ... test v = let (A a) = index (1,2) (undefined :: Z) in ... 

although for all his magic he still does this work through class classes.

+2
source

Source: https://habr.com/ru/post/1495229/


All Articles