Haskell 解压折叠

Myl*_*ies 1 haskell unzip fold

我试图弄清楚如何使用自定义版本的 fold(基本上用作 foldl)在 Haskell 中创建自定义解压缩函数,但我被卡住了。我可以得到它

unzip' :: [(a,b)] -> ([a],[b])
unzip' = fold (\x->([x!!0],[x!!1])) ([],[])
Run Code Online (Sandbox Code Playgroud)

但这会出错:

• Couldn't match expected type ‘[a]’
              with actual type ‘(Integer, Integer)’
• In the first argument of ‘tail’, namely ‘(1, 2)’
  In the expression: tail (1, 2)
  In an equation for ‘it’: it = tail (1, 2)
• Relevant bindings include
    it :: [a] (bound at <interactive>:114:1)
Run Code Online (Sandbox Code Playgroud)

据我所知,x是,(1,2)但我不确定如何将其进一步拆分为 1 和 2。这是我正在使用的 fold 函数:

fold :: (a -> b -> b) -> b -> ([a] -> b)
fold c n =
  let f [] = n
      f (x:xs) = x `c` (f xs)
  in f
Run Code Online (Sandbox Code Playgroud)

谢谢

Tre*_*edJ 5

您的 lambda 函数有几个问题。

首先,fold期望 a (a -> b -> b),从技术上讲,是一个带有两个参数的函数。现在,您的 lambda 只接受 1 个参数。由于您的fold相似foldr(从右侧折叠),第二个参数应该是累加器对象,它收集每个折叠的结果。

其次,您正在使用元组,而不是列表(如pdexter 在评论中指出的)。因此,您应该使用fstsnd函数。

在对 lambda 进行一些修改后:

\x acc -> (fst x:fst acc, snd x:snd acc)
Run Code Online (Sandbox Code Playgroud)

这会将每个元组中的第一个元素附加到累加器的第一个列表中。以及从每个元组到累加器的第二个列表的第二个元素。一些结果:

unzip' :: [(a,b)] -> ([a],[b])
unzip' = fold (\x acc -> (fst x:fst acc, snd x:snd acc)) ([],[])

unzip' [(1, 'a'), (2, 'b'), (3, 'c')]
([1,2,3],"abc")
Run Code Online (Sandbox Code Playgroud)

按照Jon 的评论,您还可以利用 lambda 中的模式匹配,替换fstsnd。这可能会增加函数的严格性。您还可以替换([], [])mempty,一个预定义的空元组。

unzip' = fold (\(x, y) (xs, ys) -> (x:xs, y:ys)) mempty
Run Code Online (Sandbox Code Playgroud)

提示:在进入unzip函数之前,您可以先隔离并测试 lambda fold

  • `fst` 和 `snd` 可以替换为模式匹配,这应该在一定程度上提高严格性:`fold (\ (x, y) (xs, ys) -&gt; (x : xs, y : ys)) ([ ], [])`。如果你愿意,`([], [])` 是 `mempty`。 (2认同)