我对Haskell很新,我正在尝试一个简单的练习练习。我想编写一个删除列表的第一个和最后一个元素的函数。
我不需要检查列表的长度。我在一本书中找到了一种方法来删除第一个元素和一个反转列表的方法,但我认为这可能比它必须更复杂。我也知道除了复杂性,在第二行之后我的错误,但我不知道为什么或如何解决它。
这是我的代码:
midList :: [a] -> [a]
midList [a] = tail [a]
[a] = reverse [a]
[a] = tail [a]
[a] = reverse [a]
答案 0 :(得分:4)
要做的第一件事是确保您了解问题。特别是,如果列表没有元素,或者只有一个元素,您希望发生什么?最简单的事情可能是在这种情况下返回空列表。所以,让我们这样做。我们可以将问题分解为两部分:
Haskell前奏定义了一些我们真正不想要的功能,所以让我们隐藏它们:
import Prelude hiding (tail, init)
现在我们可以定义这些功能的更好版本。 tail
将返回除列表的第一个元素之外的所有元素,init
将返回除最后一个元素之外的所有元素。然后我们可以写
chop :: [a] -> [a]
chop xs = init (tail xs)
tail
是最容易写的。我将提供骨架,您可以填写缺失的部分。
tail :: [a] -> [a]
tail [] = ????
tail (x : xs) = ????
init
只是有点棘手。请注意,其中一个案例将是递归的。
init :: [a] -> [a]
init [] = ????
init [x] = ????
init (x : xs) = ????
答案 1 :(得分:1)
您需要在功能上组合您的步骤。您建议的代码可以重写为:
midList :: [a] -> [a]
midList xs = reverse (tail (reverse (tail xs)))
请注意,如果程序通过空列表,tail
将使程序崩溃。你可以而且应该避免这种情况:1)检查列表是否至少包含两个元素,或者2)使用drop 1
代替tail
,这只会返回[]
空列表。
如果您尝试2),您可以保留您的功能类型。相反,对于方法1),您可以使用Maybe [a]
返回类型向调用方报告错误。更具体地说:
midList :: [a] -> Maybe [a]
midList xs@(_:_:_) = Just (reverse (tail (reverse (tail xs))))
midList _ = Nothing
其中模式_:_:_
代表一个至少包含两个元素的列表。
或者,同时使用init
和tail
:前者删除最后一个元素,后者删除第一个元素。
midList :: [a] -> Maybe [a]
midList xs@(_:_:_) = Just (init (tail xs))
midList _ = Nothing
在这里要非常小心,因为一般来说最好避免使用init
和tail
等部分功能。作为一般规则,如果采用更基本的方法来完成工作,则不应使用它们,例如:使用模式匹配。
在这里,我会发现上面的代码不是最理想的。我更喜欢以下内容,编写我自己的“{安全”版本的init
来删除最后一个元素(如果有的话),否则报告错误。
midList :: [a] -> Maybe [a]
midList (_:xs@(_:_)) = safeInit xs
midList _ = Nothing
safeInit :: [a] -> Maybe [a]
safeInit [] = Nothing
safeInit (x:xs) = case safeInit xs of
Nothing -> Just []
Just ys -> Just (x:ys)