代码之家  ›  专栏  ›  技术社区  ›  Pratik Deoghare

如何在haskell中压缩多个列表?

  •  16
  • Pratik Deoghare  · 技术社区  · 14 年前

    在蟒蛇中 zip 函数接受任意数量的列表并将它们压缩在一起。

    >>> l1 = [1,2,3]
    >>> l2 = [5,6,7]
    >>> l3 = [7,4,8]
    >>> zip(l1,l2,l3)
    [(1, 5, 7), (2, 6, 4), (3, 7, 8)]
    >>> 
    

    我怎么能 拉链 在Haskell中把多个列表放在一起?

    9 回复  |  直到 11 年前
        1
  •  34
  •   luqui    11 年前

    使用 Applicative Notation . 这是有点不愉快的使用,因为新型的包装/拆解,但如果你正在做一些不能用 zipWithn 对于相当小的n,您可能已经处于一个足够高的抽象级别,在这个级别上,符号痛苦无论如何都是不存在的。

    类型是 ZipList a 和它的应用实例将列表压缩在一起。例如:

    (+) <$> ZipList [1,2] <*> ZipList [3,4] == ZipList [4,6]
    

    使用部分应用程序将其归纳为任意数量和类型的函数:

    (+) <$> ZipList [1,2]  :: ZipList (Int -> Int)
    

    看看这里是如何部分应用(+)的?

    如果您不喜欢在任何地方添加ziplist和getziplist,您可以很容易地重新创建符号:

    (<$>) :: (a -> b) -> [a] -> [b]
    (<$>) = map
    
    (<*>) :: [a -> b] -> [a] -> [b]
    (<*>) = zipWith ($)
    

    那么符号 zipWith f a b c d ... 是:

    f <$> a <*> b <*> c <*> d <*> ...
    

    应用符号是一种非常强大和通用的技术,其范围比一般的压缩要宽得多。见 Typeclassopedia 更多关于应用符号的信息。

        2
  •  21
  •   newacct    14 年前

    可以转置列表:

    >>> import Data.List
    >>> transpose [l1,l2,l3]
    [[1,5,7],[2,6,4],[3,7,8]]
    
        3
  •  9
  •   tux21b    14 年前

    看起来还有一个 zip3 ( doc )还有一个 zip4 ( doc )Haskell中的函数。但是,由于强大的类型系统,zipn似乎很复杂。 Here is a good discussion 我在研究中发现的。

        4
  •  6
  •   David    11 年前

    GHC also supports parallel list comprehensions :

    {-# LANGUAGE ParallelListComp #-}
    
    [(x,y) | x <- [1..3]
           | y <- ['a'..'c']
           ]
    
    ==> [(1,'a'),(2,'b'),(3,'c')]
    

    我刚测试了26个并行变量,这对于所有的实际用途来说都是足够的。

    不过这有点老土(而且不标准),所以如果你写的东西很严重,ziplist可能是更好的方式。

        5
  •  4
  •   Emmanuel Touzery    11 年前

    我认为这可能是建议的最不优雅的解决方案,但是为了完整起见,应该添加这样的内容,模板haskell应该可以实现。

    这实际上包含在我认为的原始模板haskell paper(在文本中搜索zipn)中: http://research.microsoft.com/en-us/um/people/simonpj/Papers/meta-haskell/meta-haskell.pdf

    但我认为代码实际上从未起作用,请看: http://www.haskell.org/pipermail/template-haskell/2003-July/000126.html (未实现模式切片)。

    这在2003年没有实施,但今天仍然没有实施: http://www.haskell.org/ghc/docs/7.6.1/html/users_guide/template-haskell.html (不支持模式切片)

    但是,使用模板haskell实现zipwithn: http://www.haskell.org/haskellwiki/Template_Haskell#zipWithN

    我已经证实它与此测试程序一起工作:

    {-# LANGUAGE TemplateHaskell #-}
    import Zipn
    
    main = do
        let l1 = [1,2,3]
        let l2 = [5,6,7]
        let l3 = [7,4,8]
        print $ $(zipWithN 3) (,,) l1 l2 l3
    

    在zipn模块中,我粘贴了zipn,为了清晰起见,将其重命名为zipn(记住在顶部添加pragma templatehaskell)。注意,N实际上在这里被编码了两次,因为我必须给出 (,,) 作为“with”功能。你必须根据n更改逗号的数目。

    (,) 代表 \a b c -> (a,b,c)

    我想有一个拥有良好模板haskell技能的人(这不是我现在的情况)可以使用模板haskell直接创建一个zipn。

        6
  •  3
  •   ADEpt    14 年前

    这是不平凡的,但它是可行的。见 this blog post . 我不知道这是不是变成了图书馆。

    这里是 another version 更简单。这个可以剪切粘贴在这里:

    {-# LANGUAGE MultiParamTypeClasses
               , FunctionalDependencies
               , FlexibleInstances
               , UndecidableInstances
               #-}
    
    -- |
    -- Module      :  Data.List.ZipWithN
    -- Copyright   :  Copyright (c) 2009 wren ng thornton
    -- License     :  BSD3
    -- Maintainer  :  wren@community.haskell.org
    -- Stability   :  experimental
    -- Portability :  non-portable (MPTCs, FunDeps,...)
    --
    -- Provides a polyvariadic 'map'/'zipWith' like the @map@ in Scheme.
    -- For more details on this style of type hackery, see:
    --
    --    * Chung-chieh Shan, /A polyvariadic function of a non-regular/
    --      /type (Int->)^N ([]^N e)->.../
    --      <http://okmij.org/ftp/Haskell/polyvariadic.html#polyvartype-fn>
    ----------------------------------------------------------------
    module Data.List.ZipWithN (ZipWithN(), zipWithN) where
    
    -- | This class provides the necessary polymorphism. It is only
    -- exported for the sake of giving type signatures.
    --
    -- Because we can't do functor composition without a lot of noise
    -- from newtype wrappers, we use @gr@ and @kr@ to precompose the
    -- direct/list functor with the reader functor and the return type.
    class ZipWithN a gr kr | kr -> gr a where
        _zipWithN :: [a -> gr] -> [a] -> kr
    
    instance ZipWithN a b [b] where
        _zipWithN = zipWith ($)
    
    instance ZipWithN b gr kr => ZipWithN a (b -> gr) ([b] -> kr) where
        _zipWithN = (_zipWithN .) . zipWith ($)
    
    
    -- | Polyadic version of 'map'/'zipWith'. The given type signature
    -- isn't terribly helpful or intuitive. The /real/ type signature
    -- is:
    --
    -- > zipWithN :: {forall a}^N. ({a->}^N  r) -> ({[a]->}^N  r)
    --
    -- Note that the @a@ type variables are meta and so are independent
    -- from one another, despite being correlated in N across all
    -- repetitions.
    zipWithN :: (ZipWithN a gr kr) => (a -> gr) -> [a] -> kr
    zipWithN = _zipWithN . repeat
    

    如果你刚刚开始学习哈斯克尔,推迟一段时间去理解它。

        7
  •  3
  •   ertes    11 年前

    概括压缩实际上很容易。您只需编写 Applicative 组合器 ZipList :

    z :: [a -> b] -> [a] -> [b]
    z = zipWith ($)
    
    infixl 4 `z`
    

    现在,您可以压缩任意多个列表:

    f <$> xs `z` ys `z` zs
    

    或者:

    repeat f `z` xs `z` ys `z` zs
    
        8
  •  1
  •   camh    14 年前

    对于特定数量的列表,可以这样做:

    > let l1 = [1,2,3]
    > let l2 = "abc"
    > let l3 = [10.0, 11.0, 12.0]
    > let l4 = [True, False, False]
    
    > [ (e1,e2,e3,e4) | (((e1,e2),e3),e4) <- zip (zip (zip l1 l2) l3) l4 ]
    [(1,'a',10.0,True),(2,'b',11.0,False),(3,'c',12.0,False)]
    

    它不是一个通用函数,而是一个可以应用于不同数量列表的模式。

        9
  •  0
  •   Thomas Eding    14 年前

    如果所有数据都是相同的类型,则可以执行以下操作:

    import Data.List (transpose)
    
    zipAllWith :: ([a] -> b) -> [[a]] -> [b]
    zipAllWith _ []  = []
    zipAllWith f xss = map f . transpose $ xss
    
    zipAll = zipAllWith id
    

    例子:

    > zipAll [[1, 2, 3], [4, 5, 6], [7, 8]]
    [[1,4,7],[2,5,8],[3,6]]