【问题标题】:Why do we use tuples, if we can use a two dimensional list?如果我们可以使用二维列表,我们为什么要使用元组?
【发布时间】:2023-03-30 12:13:01
【问题描述】:

为这样的元组专门保留不同的数据类型配对是否有好处:

[(23, "Jordan"), (8, "Bryant")]

与仅使用二维列表相反:

[[23, "Jordan"], [8, "Bryant"]]

我知道第二段代码在 Haskell 中不起作用

【问题讨论】:

  • 列表必须包含所有相同的类型。如果你想要多种类型,那就是元组的用途。元组还保持长度固定,这有时可能很重要。列表没有。
  • 列表的每个元素都是一个元组。这些元组中的每一个都将包含相同数量和类型的元素。
  • 元组是固定长度的,但可以混合类型。列表具有任意长度,但仅包含单一类型的元素。
  • 静态类型结构的许多无类型对应物对于相同的功能来说“足够了”,即使是 Assembly,所以该参数是一个重言式,并且不建议您应该使用无类型或更少类型的结构,如果你选择了一种大量建立在其静态类型系统上的语言,例如 Haskell。

标签: list haskell tuples


【解决方案1】:

如果我们可以使用二维列表,为什么还要使用元组?

因为列表和元组在概念上是不同的东西,而类型系统为我们提供了一种有用的方式来说明和识别代码中的差异。对于许多可能的示例之一,可以定义...

type ListyPair a = [a]

...然后...

listyFst :: ListyPair a -> a
listyFst [x, _] = x

listySnd :: ListyPair a -> a
listySnd [_, y] = y

...这样:

GHCi> listyFst [3,4]
3
GHCi> listySnd [3,4]
4

但是如果列表的“对”只有一个元素,或者没有元素,会发生什么?我们将不得不抛出一个运行时错误 (yuck),或者使 listyFstlistySnd 导致 Maybe a 以便我们可以干净地处理故障。如果“对”有两个以上的元素怎么办?我们应该默默地丢弃它们,还是在这种情况下让函数也失败更好?

从强类型系统用户的角度来看,当我们用ListyPair 替换实际对时,我们丢弃了有用的信息。知道实际上只有两个元素可以避免上述所有复杂情况。

realFst :: (a, b) -> a
realFst (x, _) = x

realSnd :: (a, b) -> b
realSnd (_, y) = y 

【讨论】:

    【解决方案2】:

    “为这样的元组专门保留不同的数据类型配对是否有好处:”

    是的。使用元组的好处与数据的使用模式和任何性能要求有关。

    元组通常是不可变的并且具有可预测的大小。

    由于您正在编写一个haskell 程序,您的“字符串和整数”列表实际上是一个联合类型的列表(您可以随意调用它)...您的元组只是一个特例。

    如果您将其视为 python 代码,这一点会更加清楚。 (您提供的两个字符串都是有效的 Python 代码;我原本以为问题与 Python 相关)

    在 python 中,如果您知道元组具有固定(或可预测)的结构,您会更喜欢元组列表。

    这会让你编写如下代码:

    [ print(name) for jersey, name in list_of_tuples ]  
    

    如果您认为为对象表示付出代价不值得,您会选择使用元组,并且您更喜欢通过解包来表达每个元组引用。

    幸运的是,由于您正在编写 haskell,因此您有许多工具可以在类型系统中强烈地建模和表示问题。我认为如果您花更多时间阅读和编写一些 Haskell(Learn you a Haskell for Great Good 是一本很棒的书),您将对类型系统有更好的理解,并且您会找到答案你自己。

    如果您想全面了解函数式编程的更多信息,那么 The Little Schemer 也很精彩。

    ((un)幸运的是,在 python 中,您可以编写处理这两种数据结构类型的代码,而不必担心进入代码的类型。Haskell 要求您的思维方式与此有所不同。)

    【讨论】:

    • 有趣的是,您提到“Learn you a Haskell for Great Good”,因为我已经读过它,我的问题是受那本书启发的;我认为他们没有正确或充分地解释这个困境。顺便说一句,很棒的书!
    • 虽然谢谢你的建议,但我会研究“小计划者”!非常感谢!
    • 列表在 Haskell 中也是不可变的;你不应该在 Python 的列表推导中加入副作用表达式;这主要是关于 Python 对仅关于 H​​askell 的问题的回答,所以 -1。
    • @ErikAllik 感谢您的反馈!当我对堆栈溢出的一些奇怪电子邮件感到困惑时,我才注意到这一点。 (显然我得到了投票。)是的,我同意我对 python 的关注有点过多。但这显然是一个类型系统问题;类型系统很难。 :( 我在 ghci 中输入了它,它运行良好。前奏> let it_be = [("Whatever", 0), ("The", 1) , ("Fun", 3), ("you", 4), ("want", 5)]; 如果我擦掉 let it's python. 如果我在 haskell 中输入错误,感觉 GOOD Prelude> let it_be = [("a", 0), ("bit different on", 1), ("stack","overflow")]; 会如我们预期的错误。
    【解决方案3】:

    这个问题应该更清楚地表述为:

    为什么我们必须坚持将列表定义为恰好是一种类型的元素的集合?

    从一个角度来看,答案可能是它允许我们以严格的方式对列表进行推理,并且全新的一类操作成为可能。前任。否则你会如何为列表定义map

    从另一个角度来看,如果列表可以包含多种类型,那么该语言就不可能是静态类型的。前任。如果将列表作为参数传递给您,那么头元素的类型是什么?

    元组没有这个问题,因为你先验地定义了每个元素的类型并且长度是固定的。

    专门为元组保留不同的数据类型配对有什么好处...

    对于仅列出一种类型的元素的静态类型语言来说,这是绝对必要的,因此利益问题没有任何好处。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-11
      • 1970-01-01
      • 2014-06-22
      • 1970-01-01
      • 2021-01-14
      相关资源
      最近更新 更多