我需要使用文件夹查找列表的最小值。
这是我编写的代码:
fun minlist nil = nil
| minlist (x::xs) = List.foldr (fn (y,z) => if y < z then y else z) x xs;
但是我遇到一个错误:“重载>无法应用于类型为“列表”的参数”
我被困了一段时间。感谢您的帮助
答案 0 :(得分:1)
您的第一个子句说空列表的最小值是一个列表。
因此,(fn (y,z) => if y < z then y else z)
产生一个列表,y
和z
也必须是列表。
对于空列表,您无法产生任何有意义的值,因此您应该删除这种情况并接受编译警告,或者引发异常。
答案 1 :(得分:0)
您的表达式if y < z then y else z
具有内置名称Int.min (y, z)
。
您将空列表处理为minlist nil = nil
,这意味着“空int列表中最小的int是空列表”。但是空列表不是int,因此不能是int列表中的元素,也不能是否则返回最小int的函数的返回值。
就像molbdnilo所说的那样,您可以忍受编译警告(如果向函数提供空列表,则可能在运行时引发Match
异常),或者引发特定的异常,例如{{ 1}}给出空列表时。两者都不是好事,但后者至少可以使问题清楚。
在不使用Empty
的情况下编写此代码可能看起来像这样:
foldr
给出一些依赖于某些函数fun minimum [] = raise Empty
| minimum [x] = x
| minimum (x::xs) = Int.min (x, minimum xs)
和某些默认值foo
的递归函数bar
:
acc
您可能会注意到fun foo [] = acc
| foo (x::xs) = bar (x, foo xs)
和minimum
之间的相似之处:
foo
是acc
,是一些最小值x
是bar
。这是尝试概括Int.min
的递归方案。
给出函数minimum
:
foldr
您可能会注意到相同的地方:
fun foldr f e [] = e
| foldr f e (x::xs) = f (x, foldr f e xs);
是f
,但被设置为参数bar
是e
,但被设置为参数 acc
中唯一不适合此一般递归方案的是处理空列表。因此,您仍然必须将其与minimum
分开:
foldr
但是其余的都差不多。
第三个选择是将函数的类型签名更改为
fun minimum [] = ...
| minimum (x::xs) = foldr ...
您当前的练习可能不允许的
在不使用val minimum : int list -> int option
的情况下编写此代码可能看起来像这样:
foldr
或更妙的是:
fun minimum [] = NONE
| minimum [x] = SOME x
| minimum (x::xs) =
case minimum xs of
NONE => SOME x
| SOME y => SOME (Int.min (x, y))
将此功能转换为使用fun minimum [] = NONE
| minimum [x] = SOME x
| minimum (x::xs) = Option.map (fn y => Int.min (x, y)) (minimum xs)
的过程是相同的,但是使用不同的foldr
。
f
函数不折叠(从上面重复):
minimum
有一个问题是它主要使用stack memory。
可以通过手动评估功能来说明:
fun minimum [] = raise Empty
| minimum [x] = x
| minimum (x::xs) = Int.min (x, minimum xs)
由于无法在递归调用返回之前计算外部 minimum [1,2,3,4,5]
~> Int.min (1, minimum [2,3,4,5])
~> Int.min (1, Int.min (2, minimum [3,4,5]))
~> Int.min (1, Int.min (2, Int.min (3, minimum [4,5])))
~> Int.min (1, Int.min (2, Int.min (3, Int.min (4, minimum [5]))))
~> Int.min (1, Int.min (2, Int.min (3, Int.min (4, 5))))
~> Int.min (1, Int.min (2, Int.min (3, 4)))
~> Int.min (1, Int.min (2, 3))
~> Int.min (1, 2)
~> 1
,因此用于计算函数的堆栈内存量与列表的长度成正比。
您可以通过使用累加参数来避免这种情况:
Int.min
手动评估此功能:
fun minimum [] = raise Empty
| minimum (y::ys) =
let fun helper [] acc = acc
| helper (x::xs) acc = helper xs (Int.min (x, acc))
in helper ys y end
由于 minimum [1,2,3,4,5]
~> helper [2,3,4,5] 1
~> helper [3,4,5] (Int.min (2, 1))
~> helper [3,4,5] 1
~> helper [4,5] (Int.min (3, 1))
~> helper [4,5] 1
~> helper [5] (Int.min (4, 1))
~> helper [5] 1
~> helper [] (Int.min (5, 1))
~> helper [] 1
~> 1
是可交换的,因此您最好使用Int.min
而不是foldl
来解决此练习,方法与上面完全相同,并且会有一条尾巴-递归变量,使用较少的堆栈空间。