【问题标题】:Good functions and techniques for dealing with haskell tuples?处理haskell元组的好函数和技术?
【发布时间】:2010-04-06 16:00:12
【问题描述】:

我最近在元组和元组列表方面做了很多工作,我一直在想我是否明智。

感觉尴尬和笨拙,这对我来说表明我做错了。

例如,我编写了三个便捷函数,用于获取 3 个值的元组中的第一个、第二个和第三个值。

我错过了更好的方法吗?

是否有更通用的函数可以让您组合和操作元组数据?

以下是我正在尝试做的一些事情,感觉应该是通用的。

提取值: 我需要为大小为 2、3、4 和 5 等的元组创建 fst、snd 等版本吗?

fst3(x,_,_) = x
fst4(x,_,_,_) = x

操作值: 你可以增加对列表中每个元组的最后一个值,然后使用相同的函数增加三元组列表中每个元组的最后一个值吗?

压缩和解压缩值: 有一个zip和一个zip3。我还需要一个 zip4 吗?或者有什么方法可以创建一个通用的 zip 函数?

对不起,如果这看起来很主观,我真的不知道这是否可能,或者每次我需要一个通用解决方案时我是否在浪费时间编写 3 个额外的函数。

感谢您提供的任何帮助!

【问题讨论】:

    标签: haskell types


    【解决方案1】:

    提取值

    是的,您需要自己写fstN。但是为什么不在模式匹配中提取呢?

    压缩和解压缩值

    Data.List 已提供高达zip7。对于一般的zipN,请使用 ZipList。

    How to zip multiple lists in Haskell?

    操纵值

    不是没有扩展。由于所有的元组都是不同的类型,所以你必须创建一个类型类,例如:

    {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FunctionalDependencies #-}
    
    class Firstable a b c | a -> b, a -> c where
        firstOf :: a -> b
        restOf :: a -> c
        concatenate :: b -> c -> a
    
    instance Firstable [a] a [a] where
        firstOf = head
        restOf = tail
        concatenate = (:)
    
    instance Firstable (a,b) a b where
        firstOf = fst
        restOf = snd
        concatenate = (,)
    
    instance Firstable (a,b,c) a (b,c) where
        firstOf (x,_,_) = x
        restOf (_,x,y) = (x,y)
        concatenate x (y,z) = (x,y,z)
    
    instance Firstable (a,b,c,d) a (b,c,d) where
        firstOf (x,_,_,_) = x
        restOf (_,x,y,z) = (x,y,z)
        concatenate x (y,z,w) = (x,y,z,w)
    
    instance Firstable (a,b,c,d,e) a (b,c,d,e) where
        firstOf (x,_,_,_,_) = x
        restOf (_,x,y,z,w) = (x,y,z,w)
        concatenate x (y,z,w,t) = (x,y,z,w,t)
    

    那么你可以使用

    incFirst :: (Num b, Firstable a b c) => a -> a
    incFirst x = (1 + firstOf x) `concatenate` restOf x
    
    main = do
        print $ map incFirst [(1,2),(3,4),(5,6)]
        print $ map incFirst [(1,3,6,7),(2,5,-2,4)]
    

    lastOf 类似。)

    但是为什么不使用单独的函数呢?

    【讨论】:

    • 创建 5+ 个功能完全相同的功能对我来说似乎很浪费。 (不是说我有任何问题,如果有必要介意)。也许我只是喜欢非常干燥的东西。我想可能是太过分了。
    • 无耻插件:FirstableSecondableThirdable,...Nthablehackage.haskell.org/package/nthable
    【解决方案2】:

    当我开始有大元组时,我使用 Haskell 的记录语法的可怜借口给每个元素命名,例如,

    data LatticeOperations a = LO { bot :: a
                                  , top :: a
                                  , glb :: a
                                  , lub :: a
                                  , le  :: a
                                  }
    

    这是一个五元组,但名称变成了选择单个元素的函数。

    对于更改元组,您有记录更新语法。在我刚刚给出的示例中,只替换一个元素是没有意义的,但我可能会优化偏序并替换三个元素

    lattice { le = le', glb = glb', lub = lub' }
    

    当然,如果你有一个很大的记录并且只是想增加你可以做类似的事情

    data FatRecord = FR { count :: Int, ... }
    
    fat = fat { count = count fat + 1 }
    

    我认为记录语法对 zip 和 unzip 没有帮助。

    【讨论】:

      【解决方案3】:

      一旦元组的大小超过 3 左右,和/或相同的元组类型被广泛使用,最好使用记录。

      【讨论】:

        【解决方案4】:

        如果不使用 Template Haskell 之类的扩展,就无法泛化元组大小。因此,如果我们只考虑普通的 haskell:是的,您确实需要为每个元组大小编写 fst 等版本,不,您不能编写通用的 zip 方法。

        【讨论】:

        • 这是因为元组的每个大小都是不同的类型。在类型系统中没有办法只说“元组”,因为不存在这样的类型——有对、3 元组和 4 元组,它们都是不同的东西。
        【解决方案5】:

        我最近发现 {-# LANGUAGE RecordWildCards #-} 允许记录使用字段选择器作为值 - 像这样: 数据 R = R {a::Int, b::String, c::Bool}

        testA R{..} = a > 0

        或 .. = R {..} 其中 a = 7; b = "x"; c=真

        查看 GHC 手册!

        【讨论】:

          【解决方案6】:

          迟到总比不到好:试试Tuple package

          【讨论】:

            【解决方案7】:

            Haskell 内置的 fstsnd 仅支持元组对,因此您可以自己定义。如果要递增列表中的最后一个值,请反转列表,从那一端开始工作,然后将其反转。如果您希望该增量适用于列表和元组列表,只需定义一个为这些数据类型增量的新函数,并在您的增量函数中为列表调用它。 @KennyTM 已经回答了zipN 的问题。

            在 Haskell 中使用列表和元组与许多语言略有不同,但经过一段时间后,它们会感觉特别自然和强大。

            【讨论】:

            • 对不起,我不清楚我的意思(我已经更正了这个问题)。我的意思不是:你可以增加一个对列表的最后一个值,然后使用相同的函数来增加一个三元组列表的最后一个值吗?我的意思是:你可以增加对列表中每个元组的最后一个值,然后使用相同的函数来增加三元组列表中每个元组的最后一个值吗?很抱歉造成混乱!
            猜你喜欢
            • 1970-01-01
            • 2012-12-30
            • 1970-01-01
            • 2011-05-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-04-11
            • 1970-01-01
            相关资源
            最近更新 更多