在不使用模式匹配的情况下获取列表中的最后一个元素

时间:2018-12-03 01:20:55

标签: haskell

我不断收到“错误:分析输入内容'|'的错误”,有人可以告诉我原因吗?我已经重写了它以确保所有空格正确 这是我的代码:

 mylast :: (Eq a) => [a] -> [a]  
 mylast [] = []  
 mylast (x:xs)  
   | xs == [] : x  
   | otherwise = mylast xs   

2 个答案:

答案 0 :(得分:7)

解决该确切错误所需的最小更改只是为了解决可能是错字的问题:您写了xs == [] : x,可能是xs == [] = x的意思。所以:

mylast :: (Eq a) => [a] -> [a]
mylast [] = []
mylast (x:xs)
  | xs == [] = x
  | otherwise = mylast xs

这将给您键入错误,因为x是一个列表元素,并且您说mylast返回一个列表。您可以通过使其成为单例列表[x]来解决此问题,如下所示:

mylast :: (Eq a) => [a] -> [a]
mylast [] = []
mylast (x:xs)
  | xs == [] = [x]
  | otherwise = mylast xs

从那里,我有一些风格上的评论。

  1. 我希望您的想法是返回一个列表,这样,如果输入为空,则无需抛出错误。但是,由于我们肯定最多返回一个元素,因此您可以考虑使用Maybe代替该角色[];它提供了最多一个元素的类型级别保证。
  2. 不幸的是,Eq a约束是由于您写了xs == []而产生的,实际上并不需要在任何元素上调用(==),但是仍然需要用户提供实现(==)在元素上。检查列表是否为空的标准方法是调用null或直接使用模式匹配,而这两种模式都不需要Eq

结合这两个想法,我们得到:

mylast :: [a] -> Maybe a
mylast [] = Nothing
mylast [x] = Just x -- convenient syntax sugar for mylast (x:[]) = Just x
mylast (x:xs) = mylast xs

这对我来说很惯用。

答案 1 :(得分:1)

如果您真的想避免编写任何模式,则最简单的方法可能是foldl'

mylast :: [a] -> Maybe a
mylast = foldl' (\_ x -> Just x) Nothing

如果愿意,可以深入了解列表foldr上的原始变形:

mylast :: [a] -> Maybe a
mylast xs = foldr (\x r _ -> r (Just x)) id xs Nothing

但这有点难以理解。

foldl'foldr最终是使用模式匹配实现的,因为这是检查Haskell中列表的基本底层方法。因此,没有任何方法可以真正完全避免它。