我正在处理一个找到列表中最大数字的函数。
fun maxValue(xs) =
case xs of
[] => []
| first::rest => if ((first)>hd(rest))
then maxValue(first :: tl(tl(rest)))
else maxValue(rest)
val list = [1,2,4,8,3]
val ans = maxValue list
但是我收到以下错误:
Standard ML of New Jersey v110.78 [built: Thu Aug 31 03:45:42 2017]
= stdIn:2.5-6.40 Error: case object and rules don't agree [overload conflict]
rule domain: [> ty] list list
object: [> ty] list
in expression:
(case xs
of :: (x,nil) => x
| :: (xs,rest) =>
if hd <exp> > hd <exp>
then maxValue (<exp> :: <exp>)
else maxValue (tl <exp>))
我不明白错误意味着什么,代码为什么不编译。有什么我想念的东西,我该如何解决这个问题?
修改:为了清晰起见,将某些变量名称从xs更改为第一个。
答案 0 :(得分:3)
我对你的功能有几个问题:
first
的头?在您的示例中first
没有头,因为它是1
,i。即您作为参数传递的列表的头部rest
尾巴的尾巴?为了解决这类递归问题,我使用了一个辅助函数,它将递归结构作为第一个参数,可能的结果作为第二个参数。这是我的尝试:
fun maxValue xs =
let
fun helper xs chosen =
case xs of
[] => chosen
| first :: [] =>
if first > chosen
then first
else chosen
| first :: rest =>
if first > hd rest
then helper rest first
else helper rest (hd rest)
in
helper xs 0
end
在空列表的情况下,我只是返回0以避免复杂化。
最近我使用的是Poly/ML而不是SML / NJ。错误似乎更友好
答案 1 :(得分:2)
我的教授非常友好地向我提供了以下替代解决方案和解释:
您的递归案例有几个问题:您将获取列表第一个元素的头部,并将其与if语句中列表的第二个元素进行比较。然后你将你的函数应用到列表的第一个元素的头部,列表的第一个元素与第一个元素被删除?
以下是我建议实现此功能的方法:
fun maxValue(xs) =
case xs of
x::[] => x
| first::rest =>
let
val maxRest = maxValue(rest)
in
if first > maxRest
then first
else maxRest
end
答案 2 :(得分:2)
您的功能不安全,因为它假定hd rest
,tl rest
和tl (tl rest)
具有有意义的值,但当rest
为空时,这些会导致raise Empty
。这里有两个安全的变体:1)maximum1
假定存在至少一个元素,但不假设它是什么。 2)当列表为空时,maximumOpt
返回NONE
:
fun maximum1 x xs = foldl Int.max x xs
fun maximumOpt [] = NONE
| maximumOpt (x::xs) = SOME (maximum1 x xs)
在第一种情况下,问题在于给函数输入;在第二种情况下处理其输出。根据您在程序中处理错误的最佳机会,可能会更好。或者其他可能更好。
编辑:根据提供具有各种缺点的不安全解决方案的其他答案(不合理的默认值,模式匹配并非详尽无遗),这是一个引发有意义异常的简短变体:
fun maximum [] = raise Empty
| maximum (x::xs) = foldl Int.max x xs
使用显式递归而不是折叠:
fun maximum [] = raise Empty
| maximum [x] = x
| maximum (x::y::xs) = maximum (Int.max(x, y)::xs)