【问题标题】:Haskell type math problemHaskell 类型的数学问题
【发布时间】:2011-09-17 20:22:54
【问题描述】:

我是 haskell 初学者。我尝试编写将返回倒数第二个列表元素的函数。

我是这样开始的:

lastButOne :: [a] -> a
lastButOne list = if null list
           then 
                0
           else 
                length list

0 字符串我得到错误:

Couldn't match type `a' with `Int'
      `a' is a rigid type variable bound by
          the type signature for lastButOne :: [a] -> a

我明白了。但我能在这里做什么?我不知道列表类型。我可以在这里放什么?

谢谢。

【问题讨论】:

  • 不清楚您真正想要返回什么。也许有意义吗?
  • @Craig "倒数第二个元素"
  • 使类型签名返回一个整数而不是列表类型的“a”

标签: list haskell types


【解决方案1】:

0 是 int 类型,因此它不适用于所有 a。我建议改为使用Maybe a,如下所示:

lastButOne :: [a] -> Maybe a
lastButOne [] = Nothing
lastButOne [x] = Nothing
lastButOne xs = Just $ list !! (length xs - 2)

使用警卫:

lastButOne :: [a] -> Maybe a
lastButOne xs | length xs > 1 = Just $ list !! (length list - 2)
              | otherwise = Nothing

使用 Maybe 的 MonadPlus 实例:

import Control.Monad (guard)

lastButOne :: [a] -> Maybe a
lastButOne list = guard (length list > 1) >> return (list !! (length list - 2))

一般来说,对于 MonadPlus 的任何实例:

import Control.Monad (guard)

lastButOne :: MonadPlus m => [a] -> m a
lastButOne list = guard (length list > 1) >> return (list !! (length list - 2))

尽管您必须在某个地方向编译器指定您希望结果为 Maybe。通常这会被类型推断,因为它会被传递给一个期待 Maybe 的函数。

请记住,这是在 O(n) 中运行的。您可能不想找到列表的倒数第二个元素......为什么需要这样做?至少考虑改用数组。

【讨论】:

  • @delnan 我很担心!!和 -,不是函数应用程序。
  • @delnan 在 ghci 中测试。括号是必需的。
  • 我会避免使用length 进行/使用递归调用,因为这会导致操作O(n^2)。相反,尝试像 Bearzk 的答案中那样的模式匹配或使用反向:lastButOne = listToMaybe . drop 1 . reverse
  • @Thomas 它仍然是 O(n)。你在说什么?长度是 O(n),我没有使用任何显式递归。我还包括了一个模式匹配版本;我的答案中有相同功能的版本......当然,我承认我的解决方案比较慢,因为它可能会递归列表两次,但谁在乎真正的问题是他使用了错误的数据结构手头的算法?
  • 回复:“你可能不想找到列表的倒数第二个元素”这几乎可以肯定是许多人在学习一门新语言时使用的一组 99 个基本问题之一,并且不是性能关键应用程序的一部分。
【解决方案2】:

炫耀的解决方案

lastButOne :: [a] -> a
lastButOne [] = error "empty list"
lastButOne [x] = x
lastButOne xs = head $ drop 1 $ reverse xs

【讨论】:

  • lastButOne = head . drop 1 . reverse 更好。
【解决方案3】:

我也是 Haskell 的新手。我认为您的问题是代码中的0。我真的不知道如何解决它,但这是我的解决方案,希望对您有所帮助:

lastButOne :: [a] -> a

lastButOne [] = error "empty list"
lastButOne [x1] = error "only one element"
lastButOne [x1,x2] = x1
lastButOne (x:xs) = lastButOne xs

该函数从头开始删除元素,直到剩下 2 个元素,然后这两个中的第一个是 last-But-One。

【讨论】:

    【解决方案4】:

    签名说“这个函数接受一个包含任何类型元素的列表,并返回列表中所有元素的相同元素的值”。另一方面,代码说“这个函数接受一个包含任何类型元素的列表,并返回一个数字”。 that 的正确类型签名应该是 [a] -> Int*(“这个函数接受一个包含任何类型元素的列表,并返回一个任何类型的值 Num”)。

    但是由于您想返回倒数第二个元素而不是列表的长度,因此类型签名是正确的,但代码不正确。您必须从列表中取出一些项目,或者以某种方式error,使用Maybe 返回类型,使用模式匹配并仅省略这些情况的子句,返回undefined :: a)句柄列表没有倒数第二个元素,因为它们的元素少于两个。

    (*) 如果前奏曲 length 不是一心只为表演而放弃 Ints,那将是 (Integral b) => [a] -> b

    【讨论】:

    • 那应该是 Integral b,而不是 Num b,不是吗?
    • @monadic:会说得通——但Data.List.genericLength 出于某种原因使用Num。我仍然对其进行了更改并添加了一条注释,为什么它在当前版本中是 Int
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-19
    • 1970-01-01
    • 2012-03-12
    • 2010-12-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多