初学者 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 function: last []
给出了一个错误,因为是空列表中找不到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
我正在尝试创建一个函数来生成列表中的最后一项。我想使用反向和 !!。这是我目前所拥有的:
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 function: last []
给出了一个错误,因为是空列表中找不到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