函数将元组解压为两个列表Haskell

函数将元组解压为两个列表Haskell,haskell,Haskell,我正在寻找一个函数,它获取元组列表[(a,b)],并将其解压缩到[a]和[b]。我看过Hoogle,但我能找到的唯一函数是unzip,它接受一个元组并返回元组中的列表。有没有一个函数可以做到这一点?如果不是,是否应该使用解压,然后创建一个函数,返回[a]的第一个列表和[b]的第二个列表您编写了一个函数,返回[a]的第一个列表和[b]的第二个列表。嗯,unzip就是这样做的,将两个列表成对返回。在Haskell中,返回一对是返回两件东西最直接的方法 我想你认为你需要的不是解压,但你不需要。例如,假

我正在寻找一个函数,它获取元组列表
[(a,b)]
,并将其解压缩到
[a]
[b]
。我看过Hoogle,但我能找到的唯一函数是
unzip
,它接受一个元组并返回元组中的列表。有没有一个函数可以做到这一点?如果不是,是否应该使用
解压
,然后创建一个函数,返回
[a]
的第一个列表和
[b]
的第二个列表您编写了一个函数,返回
[a]
的第一个列表和
[b]
的第二个列表。嗯,
unzip
就是这样做的,将两个列表成对返回。在Haskell中,返回一对是返回两件东西最直接的方法

我想你认为你需要的不是
解压
,但你不需要。例如,假设您有一个
[(Int,String)]
,您所要做的就是将所有
Int
s相乘以获得
n
,将
字符串连接起来以获得
s
,然后返回
s++“=”+++show n
。你可以这样做:

input=[(1,“x”),(2,“y”),(3,“z”)]
output=let(nums,strings)=解压输入——nums和strings是两个列表
n=产品nums
s=concat字符串
在s++“=”+++中显示n
解压::[(a,b)]->([a],[b])
确实返回两个列表
[a]
[b]
,它们只是包装在一对中,因为所有Haskell函数类型都只有一个输入和一个输出

为了提取结果,您可以将模式匹配与
大小写一起使用

-- | Example input.
input :: [(Int, Char)]
input = [(1, 'A'), (2, 'B'), (3, 'C'), (4, 'D')]
或者,因为此模式是完整的(无可辩驳,忽略非终止),具有
let
where
绑定:

main = do
  let
    (fs, ss) = unzip input
  print fs
  print ss
如果您只需要第一个列表或第二个列表,可以分别提取它们:

main = do

  let fs = map fst input
  print fs

  let ss = map snd input
  print ss
但是,如果要同时使用
map fst
map snd
,则会遍历输入列表两次,因此
unzip
更可取,因为它只遍历一次

使用元组是从一个函数返回多个结果的正常方式,当结果只有少数(2–3)时。如果不止这些,则最好使用记录类型,以便为字段指定清晰的名称

返回多个结果的另一种方法是连续传递样式(CPS),在本上下文中,这意味着将两个结果传递给用户指定的“回调”函数,而不是在元组中返回它们:

unzipCps
  :: [(a, b)]           -- ^ Input list
  -> ([a] -> [b] -> c)  -- ^ Output callback
  -> c

unzipCps ((x, y) : rest) returnBoth
  = unzipCps rest prependBoth
  where
    prependBoth xs ys = returnBoth (x : xs) (y : ys)

unzipCps [] returnBoth = returnBoth [] []

main = do

  -- Equivalent to the original ‘unzip’.
  let (fs, ss) = unzipCps input (,)
  print fs
  print ss

  -- The result type (‘c’ in ‘unzipCps’)
  -- can be anything, including an ‘IO’ action.
  unzipCps input $ \ fs ss -> do
    print fs
    print ss

有时,当使用
GADTs
/
RankNTypes
时,这种风格是必要的,或者有助于实现性能优化,但是在这种情况下,使用它没有特别的优势,而且它有不同的性能特点。

您认为您的函数类型是什么?
unzip
正是您所需要的。你能解释一下为什么你认为它不合适吗?您可以编写一个函数,返回
[a]
的第一个列表和
[b]
的第二个列表。嗯,
unzip
就是这样做的,将两个列表成对返回。如果不是成对的,您希望如何获得这两个列表?我想你认为你需要的不是
解压
,但你不需要。也许给我们一个关于你试图达到的总体目标的线索会对你有所帮助。@Enlico“如果不是成对的话,如何……获得这两个列表?”
foo xs k=let{(a,b)=unzip xs}。在k a b
@WillNess中,你不是还在使用
(a,b)=unzip xs unzip xs?
main = do

  let fs = map fst input
  print fs

  let ss = map snd input
  print ss
firsts :: [(a, b)] -> [a]
firsts = map fst

seconds :: [(a, b)] -> [b]
seconds = map snd

main :: IO ()
main = do
  let
    fs = firsts input
    ss = seconds input
  print fs
  print ss
unzipCps
  :: [(a, b)]           -- ^ Input list
  -> ([a] -> [b] -> c)  -- ^ Output callback
  -> c

unzipCps ((x, y) : rest) returnBoth
  = unzipCps rest prependBoth
  where
    prependBoth xs ys = returnBoth (x : xs) (y : ys)

unzipCps [] returnBoth = returnBoth [] []

main = do

  -- Equivalent to the original ‘unzip’.
  let (fs, ss) = unzipCps input (,)
  print fs
  print ss

  -- The result type (‘c’ in ‘unzipCps’)
  -- can be anything, including an ‘IO’ action.
  unzipCps input $ \ fs ss -> do
    print fs
    print ss