【问题标题】:Position based tuple pattern match in HaskellHaskell中基于位置的元组模式匹配
【发布时间】:2013-08-04 21:32:50
【问题描述】:

是否可以在 Haskell 中对元组进行模式匹配,但不知道元组的维度?我想创建一个针对任何元组的函数,第一个元素是A,例如:

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

我知道有Data.Tuple.Select 模块,我可以这样使用它:

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

但这是唯一的方法还是 Haskell 有一些默认机制来匹配任何维度元组?

【问题讨论】:

    标签: haskell pattern-matching tuples


    【解决方案1】:

    您可以使用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
    

    【讨论】:

      【解决方案2】:

      如果您不想使用类型类,也可以使用嵌套元组。因此,不是有一个 (A, B, C, D) 类型的元组,而是一个 (A, (B, (C, D))) 的元组。

      然后,您可以轻松地匹配嵌套多深的元组的第一个元素,如下所示:

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

      【讨论】:

      • 感谢您提供此解决方案!我会用它。它没有回答我的问题(因为它使用嵌套元组),但它非常非常酷。
      【解决方案3】:

      任何解决方案都必须以某种方式泛化元组,因为默认情况下它们只是不相交的类型。最常见的解决方案将使用类型类来索引“具有第一个元素”的类型的概念,例如 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 ...
      

      尽管它具有魔力,但它仍然通过类型类来完成这项工作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-09-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多