【问题标题】:Haskell :: Recursion for List of TuplesHaskell :: 元组列表的递归
【发布时间】:2018-02-20 21:47:22
【问题描述】:

我正在映射一个元组并设法使其适用于单个元组 (a, a)。但是当我将元组更改为[[(a, a)]] 时,它会说“无法将[(a, a)] 的预期类型与(a, a) 匹配。

    mapTuple :: (a -> b) -> [[(a, a)]] -> [(b, b)]
    mapTuple f [] = []
    mapTuple f ((a1, a2) : xs) = (f a1, f a2) : mapTuple f xs

    myfunc :: Int -> Int
    myfunc xk = xk + 1


    myTup = [[(1,2),(5,6),(9,10)]] :: [[(Int, Int)]]
    test = mapTuple myfunc myTup

还不能解决这个错误。我在这里遗漏了一些东西。提前感谢您的帮助。

【问题讨论】:

  • 这很合逻辑不是吗?
  • 如果输入为[[(1,1),(2,2)],[(3,3)]],你想得到什么结果?
  • 要不要展平输入列表?您刚刚描述的函数的类型为(a -> b) -> [[(a, a)]] -> [[(b, b)]]
  • [[(2,2),(3,3)],[(4,4)]] 的类型错误。你想要[(b, b)],但它的类型是[[(b, b)]]
  • “应该是[[(2,2),(3,3)],[(4,4)]]”。 “当我展平列表时它会起作用”。选择一个。

标签: haskell recursion tuples


【解决方案1】:

这不是对您问题的一对一回答。但是我不得不说,在 Haskell 中,元组并不是像 (a,a) 这样的类型的理想表示。元组用于对不同类型进行分组,例如 (a,b)

你的工作基本上需要一个fmap 覆盖元组,但fmap 只影响元组的第二项。然后你可以从元组为一个新的仿函数实例创建一个“新类型”,其中fmap 会影响这两个项目。但是……你已经有了。这是[]。那么为什么不使用[] 来代替元组,如果您深入研究应用类型,这会带来极大的简单性?

mapNestedList :: (a -> b) -> [[[a, a]]] -> [[b, b]]
mapNestedList f = ((map f <$>) =<<)

Prelude> mapNestedList (+1) [[[1,2],[5,6],[9,19]]]
[[2,3],[6,7],[10,20]]

那么这里发生了什么?

  • map (+1) 的类型是Num a =&gt; [a] -&gt; [a]
  • 记住&lt;$&gt;实际上是内联fmap(map (+1) &lt;$&gt;)的类型原来是(Num a, Functor f) =&gt; f [a] -&gt; f [a]
  • 这意味着我们有一个包含列表的函子,我们将对这些列表应用一个函数。这个函子可以是Maybe 类型或其他类型。在这种特殊情况下,我们的函子恰好是另一个 []
  • 然后是(=&lt;&lt;) 运算符,它实际上是一元绑定(&gt;&gt;=) 的翻转版本。 (=&lt;&lt;) 的类型是 Monad m =&gt; (a -&gt; m b) -&gt; m a -&gt; m b。至于这种类型签名,在这种特殊情况下,a 类型变量代表Num c =&gt; [[c]]b 代表Num c =&gt; [c] 之类的类型,产生m b 解析为Num c =&gt; [[c]]m a解析为Num c =&gt; [[[c]]]
  • 因此,从上面给定的(a -&gt; m b) 类型变量我们可以使用((map (+1) &lt;$&gt;)((map (+1) &lt;$&gt;) =&lt;&lt;) 的最终类型结果是(Num b, Monad m) =&gt; m (m [b]) -&gt; m [b]

再一次……

Prelude> mapNestedList (+1) [[[1,2],[5,6],[9,19]],[[10,20],[30,40]]]
[[2,3],[6,7],[10,20],[11,21],[31,41]]

【讨论】:

  • 感谢 Redu 的评论。同意一个元组不是像(a,a) 这样的类型的理想表示。如果它是您建议的列表,则可以与mapNestedList 一起使用。
【解决方案2】:

当然,当您将类型更改为 [[(a,a)]] 时,您的 mapTuple 将无法工作,因为 ((a1, a2) : xs) 仍然具有 [(a,a)] 类型。

如果您想将 mapTuple 应用于元组列表而不是元组列表,则根本不需要更改 mapTuple。

让我们看一下类型: mapTuple(在你改变它之前)有类型(a -&gt; b) -&gt; [(a,a)] -&gt; [(b,b)]

将 mapTuple 部分应用于 myfunc 我们得到 [(a,a)] -&gt; [(b,b)]

从 cmets 中,您需要一个接受 [[(1,1),(2,2)],[(3,3)]] :: [[(a,a)]] 并返回 [[(2,2),(3,3)],[(4,4)]] :: [[(b,b)]] 的函数

所以我们想把这个偏函数应用到[[(a,a)]]中的每一个[(a,a)],得到[[(b,b)]]

所以总的来说,我们想要一个具有以下类型的函数: ([(a,a)] -&gt; [(b,b)]) -&gt; [[(a,a)]] -&gt; [[(b,b)]]

这可以简化为(a -&gt; b) -&gt; [a] -&gt; [b]。好吧,已经有一个功能可以为我们做到这一点!常规旧地图。

所以使用你的旧 mapTuple 类型为(a -&gt; b) -&gt; [(a, a)] -&gt; [(b, b)] 我们通过以下方式得到正确的结果:

test = map (mapTuple myfunc) myTup

希望这是有道理的,如果不能随时要求澄清:)

【讨论】:

  • 这是一个准确而准确的答案!!!是的,这真的很有帮助。我把你的解释写在一张纸上以便理解。你把这部分搞定了 “从 cmets 中你想要一个接受 [[(1,1),(2,2)],[(3,3)]] :: [[(a,a)]] 并返回 [[(2,2),(3,3)],[(4,4)]] :: [[(b,b)]] 的函数所以我们想把这个部分函数应用到 [[(a,a)]] 中的每个 [(a,a)] 以获得 [[(b,b)]] ." 对我来说新的东西是对(a -&gt; b) -&gt; [a] -&gt; [b] 的简化,我认为我需要对此进行更多研究。它看起来像数学。这应该是一个很好的参考。再次感谢!
猜你喜欢
  • 2013-12-05
  • 2019-07-21
  • 2019-03-18
  • 1970-01-01
  • 2011-07-16
  • 1970-01-01
  • 2015-03-29
  • 1970-01-01
  • 2019-03-19
相关资源
最近更新 更多