Haskell 如何在可能输出的列表中查找最大元素

Haskell 如何在可能输出的列表中查找最大元素,haskell,maybe,Haskell,Maybe,此代码有效 max_elem :: (Ord a) => [a] -> a max_elem [x] = x max_elem [] = error "No elements" max_elem (x:xs) |x > max_elem xs = x |otherwise = max_elem xs 我想要它,所以如果它们没有元素,它什么也不返回,最大元素只有x 我尝试了以下方法 max_elem :: (Ord a) => [a] ->

此代码有效

max_elem :: (Ord a) => [a] -> a 
max_elem [x] = x 
max_elem [] = error "No elements" 
max_elem (x:xs)  
    |x > max_elem xs = x 
    |otherwise = max_elem xs
我想要它,所以如果它们没有元素,它什么也不返回,最大元素只有x 我尝试了以下方法

max_elem :: (Ord a) => [a] -> Maybe a 
max_elem [x] = Just x 
max_elem [] = Nothing
max_elem (x:xs) 
    |x >  max_elem xs = Just x
    |otherwise = max_elem xs 
我犯了以下错误。请建议修复此问题

 • Couldn't match expected type ‘a’ with actual type ‘Maybe a’
      ‘a’ is a rigid type variable bound by
        the type signature for:
          max_elem :: forall a. Ord a => [a] -> Maybe a
        at <interactive>:208:13
    • In the second argument of ‘(>)’, namely ‘max_elem xs’
      In the expression: x > max_elem xs
      In a stmt of a pattern guard for
                     an equation for ‘max_elem’:
        x > max_elem xs
    • Relevant bindings include
        xs :: [a] (bound at <interactive>:211:13)
        x :: a (bound at <interactive>:211:11)
        max_elem :: [a] -> Maybe a (bound at <interactive>:209:1)

•无法将预期类型“a”与实际类型“可能a”匹配
“a”是一个刚性类型变量,由
以下项的类型签名:
马克斯·埃伦:对于所有a。Ord a=>[a]->可能是a
时间:208:13
•在“(>)”的第二个参数中,即“max_elem xs”
在表达式中:x>max_elem xs
在图案保护的stmt中
“max_elem”的方程式:
x>最大元素x
•相关绑定包括
xs::[a](绑定时间:211:13)
x::a(绑定时间:211:11)
马克斯·埃利姆::[a]->可能是a(绑定在:209:1)

错误消息非常清楚,足以解决您的问题

|x >  max_elem xs = Just x
问题是您将
x
这是
a
max\u elem
这是
可能是a
进行比较。这就是为什么你会收到这样的错误信息。您可以使用下面的代码解决这个问题

max_elem :: (Ord a) => [a] -> Maybe a 
max_elem []     = Nothing
max_elem (x:xs) = case (max_elem xs) of
  Nothing -> Just x
  Just y  -> if x > y then Just x else Just y

由于这一行,您得到了错误:
x>max_elem xs
max_elem xs
具有类型
可能是a
,其中
a
是列表的一个元素。它具有类型
a
。不能比较不同类型的值<代码>a和
可能a
是不同的类型。见Haskell等式表:

=
运算符替换为
,您将得到相同的表

您可以通过将
x>max_elem xs
替换为
Just x>max_elem xs
来解决代码中的问题。这对你有意义吗

如您所见,
可能一个
数据类型有
Ord a=>Ord(可能是)
实例,这实际上非常方便!因此,您可以以更简洁的方式实现您的功能,以利用此
Ord
实例:

max_elem :: Ord a => [a] -> Maybe a 
max_elem = foldr max Nothing . map Just

但是,如果您关心性能,这可能不是最有效的解决方案。

我们可以概括此任务,并使用所有可折叠的
解决方案。因此,我们在这里使用折叠某种可折叠结构的函数。我们可以通过函数
max来实现这一点。只是
,作为初始元素
无:

max_elem :: (Ord a, Foldable f) => f a -> Maybe a 
max_elem = foldr (max . Just) Nothing
注意,这是因为Haskell将
可能
定义为
Ord
的一个实例,假设
a
Ord
的一个实例,并且它以
比任何
元素小的方式实现它

这使得上述定义可能有点“不安全”(从这个意义上说,我们在这里依赖这样一个事实,即从我们有一个
Just x
的那一刻起,
max
将选择这样的
Just x
,而不是
Nothing
)。当我们使用
min
时,这将不起作用(除非使用一些技巧)

我们还可以使用模式保护,从而以不同的方式解决列表为空的情况,如:

max_elem :: Ord a => [a] -> Maybe a 
max_elem [] = Nothing
max_elem l = Just (maximum l)

问题是
x>max_elem xs
max_elem xs
可能是a
,而不是
a
,这意味着它可能不返回任何内容。但是,您知道如果
xs
为空,它只会返回
Nothing
,但是您知道
xs
不会为空,因为您匹配了使用[x]时它会返回
的情况。您可以通过编写“非空”最大值来利用这一事实:

或者,使用
max

max_elem_ne :: Ord a => a -> [a] -> a
max_elem_ne m []     = m
max_elem_ne m (x:xs) = max_elem (max m x) xs
您可以将第一个参数视为“到目前为止”看到的最大值,将第二个列表参数视为其他候选列表

在最后一种形式中,您可能已经注意到,
max\u elem\u ne
实际上是一个左折叠,因此您甚至可以只写:

max_elem_ne :: Ord a => a -> [a] -> a
max_elem_ne = foldl' max
现在,使用
max\u elem\u ne
,您可以编写原始
max\u elem

然后你可以写:

max_elem :: Ord a => [a] -> Maybe a
max_elem []     = Nothing
max_elem (x:xs) = Just (max_elem_ne x xs)
因此,您不必进行任何无关的检查(就像您在结果上进行冗余模式匹配时所做的那样),而且整个过程都是类型安全的

您还可以使用
uncon::[a]->可能(a[a])
实用程序函数和
fmap
uncurry
来编写:

max_elem :: Ord a => [a] -> Maybe a
max_elem = fmap (uncurry max_elem_ne) . uncons

在“(>)”的第二个参数即“max_elem xs”中,无法将预期类型“a”与实际类型“Maybe a”匹配。我似乎很清楚您可以尝试导入数据。列表(findIndex)
findIndex(=最大x)x
,但最好找到您的错误。我确实更喜欢将特定操作划分为特定函数。有计算,有错误检查和输入验证。在我看来,在一个单独的函数中,每一个函数都更干净。我会使用
,否则只使用y
,否则我们会重新计算最大值,导致指数爆炸@谢谢!已编辑。“max_elem[x]=Just x”可以是skipped@max630谢谢编辑。
fmap最大值(如果为空x,则没有其他值,只有x)
可能更简单。不需要将列表中的每个元素都包装在
中,只需要一个非空的列表本身。好吧,在现实世界中,我不会首先对列表使用
maximum
函数。与
maximum
函数的低效性相比,将每个元素包装到
maximum
中的成本微不足道,后者很可能包含空间泄漏。
maximum
不过是使用
Max
monoid对
foldMap
进行包装;这和你上面写的没什么不同。是的,正如我在回答中所说的,我的实现也不完美。它也有同样的问题。但是我想Haskell初学者暂时不要深入研究这些事情是可以的。对不起,我想回来并注意我的建议也可以简化为
如果为空x,则没有其他最大x
,因为
最大值
基本上只是假设折叠不会重新折叠
max_elem :: Ord a => [a] -> Maybe a
max_elem = fmap (uncurry max_elem_ne) . uncons