【问题标题】:Defining a length function using tail使用 tail 定义长度函数
【发布时间】:2016-11-08 07:04:36
【问题描述】:

我对 Haskell 很陌生,我正在尝试定义自己的长度函数,如下所示:

lengthz :: [a] -> a lengthz [] = 0 lengthz n = 1 + length (tail n)

为什么不能编译?或者,我的逻辑有问题吗?

谢谢!

【问题讨论】:

  • 请注意,最好避免使用tail,因为当您将空列表传递给它时,它可能会使您的程序崩溃。您应该尽可能使用(详尽的)模式匹配,这不会有同样的问题——例如lengthz (x:xs) = 1 + lengthz xs.

标签: list haskell


【解决方案1】:

首先,您在对lengthZ 的递归调用中有错字。解决这个问题,我们遇到了一个新的类型错误:

没有(Num a)的实例

这告诉我们,为了使用函数(+),我们必须在类型声明中包含类型类Num 作为约束。我们还为列表的元素包含了一个不同的类型变量,以便该函数可以应用于包含任何类型元素的列表。因此,我们将函数重写如下:

lengthz :: Num b => [a] -> b
lengthz [] = 0
lengthz n = 1 + lengthz (tail n)

正如我们所期望的那样工作:

ghci>> lengthz [1,2,3]
3
ghci>> lengthz []
0

【讨论】:

  • 为什么不lengthz :: Num a => [x] -> a你根本不使用列表的内容。
  • Integral b 的约束可能会更好;列表的“长度”为 1.5 意味着什么?如有必要,让调用者将长度转换为实际类型(例如,计算平均值)。 (例如,genericLengthz = fromIntegral . lengthz。)
  • @chepner 因为我们的定义甚至不会导致我们获得非整数类型,这不是一个非常糟糕的理由吗?我知道前奏 length 功能以这种方式受到限制,但认为人们认为这是一种不便。
  • Prelude.length 更受限制;它只返回IntData.List.genericLength 泛化为 Num b => b。由于定义 lengthz 没有实际目的,我认为值得以某种方式将其与现有函数区分开来,即通过提供准确反映可能返回值的类型约束。跨度>
【解决方案2】:

lengthz 函数的类型是 [a] -> a

这意味着您正在获取 a 事物的列表并返回一个 a 事物。如果您有Bool 的列表怎么办?您不希望函数输出Bool。无论列表中事物的类型如何,您都希望返回 Int

最简单的解决方法是将lengthz 的类型更改为[a] -> Int。这表示参数可以是任何东西的列表(a 是任何东西,[] 说它是一个列表)并且返回类型是 Int

【讨论】:

    猜你喜欢
    • 2011-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-11
    • 2012-10-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多