初学者 Haskell:用 reverse 制作最后一个函数

Beginner Haskell: Making a last function with reverse

我正在尝试创建一个函数来生成列表中的最后一项。我想使用反向和 !!。这是我目前所拥有的:

myLast :: [a] -> [a] -> Int -> a
myLast xs = (reverse xs) !! 1

我知道问题出在类型的某处,但我无法确定如何修复它。

一个函数的类型签名与你在函数中使用什么无关,它只描述了其他人如何使用这个函数你正在定义。所以通过写

myLast :: [a] -> [a] -> Int -> a

你是说,用户需要提供两个列表和整数。只是为了获得其中一个列表的最后一个元素?这没有意义。

你肯定是说

myLast :: [a] -> a

您通常应该在考虑您将如何实现该功能之前写下它。

使用该签名,您可以编写各种实现:

myLast :: [a] -> a
myLast xs = head $ reverse xs

myLast' :: [a] -> a
myLast' [l] = l
myLast' (_:xs) = myLast' xs

myLast'' :: [a] -> a
myLast'' = fix $ \f (x:xs) -> maybe x id . teaspoon $ f xs

或者你选择的任何奇怪的实现,它与签名无关。

一个不相关的说明:虽然 last 实际上是前奏中的标准函数,但它是现代 Haskell 中避免的 kind of functionlast [] 给出了一个错误,因为空列表中找不到a值!错误是不好的。因此,“理想”的写法实际上是

myLast :: [a] -> Maybe a
myLast [] = Nothing
myLast [x] = x
myLast (_:xs) = myLast xs

我建议完全不要使用 !!,而是使用 head

myLast xs = head (reverse xs)

Head returns 作为参数给出的列表的第一个元素。
如果你坚持使用!!,在Haskell中数组确实是从零开始的,这意味着!! 0获取第一个元素,!! 1第二个,等等

至于类型:myLast 采用某种类型的数组和 returns 相同类型的一项。即表示如下:

myLast :: [a] -> a

@leftaroundabout 在他的回答中更好地涵盖了这种方式。

根据@leftaroundabout 的回答,这里有一个可以满足您要求的实现:

safeHead :: [a] -> Maybe a
safeHead [] = Nothing
safeHead (x:_) = Just x

myLast :: [a] -> Maybe a
myLast [] = Nothing
myLast xs = safeHead $ reverse xs

Maybe类型构造如下(来自Hackage):

data  Maybe a  =  Nothing | Just a
  deriving (Eq, Ord)

myLast [1, 2, 3, 4],例如,会returnJust 4。如果要使用值 4,可以使用 Data.Maybe module 中的函数 fromJust (fromJust (Just 4) returns 4)。 fromJust 定义如下:

-- | The 'fromJust' function extracts the element out of a 'Just' and
-- throws an error if its argument is 'Nothing'.
--
-- ==== __Examples__
--
-- Basic usage:
--
-- >>> fromJust (Just 1)
-- 1
--
-- >>> 2 * (fromJust (Just 10))
-- 20
--
-- >>> 2 * (fromJust Nothing)
-- *** Exception: Maybe.fromJust: Nothing
--
fromJust          :: Maybe a -> a
fromJust Nothing  = error "Maybe.fromJust: Nothing" -- yuck
fromJust (Just x) = x