SML,使用foldr定义列表的最小值
我需要使用foldr找到列表的最小值 以下是我编写的代码:SML,使用foldr定义列表的最小值,sml,Sml,我需要使用foldr找到列表的最小值 以下是我编写的代码: fun minlist nil = nil | minlist (x::xs) = List.foldr (fn (y,z) => if y < z then y else z) x xs; fun minlist nil=nil |minlist(x::xs)=List.foldr(fn(y,z)=>如果y无法应用于'a list'类型的参数” 我被困了一段时间。感谢您的帮助。您的第一句话说空列表的最小值是一个列表。
fun minlist nil = nil
| minlist (x::xs) = List.foldr (fn (y,z) => if y < z then y else z) x xs;
fun minlist nil=nil
|minlist(x::xs)=List.foldr(fn(y,z)=>如果y
但是,我得到一个错误:“重载>无法应用于'a list'类型的参数”
我被困了一段时间。感谢您的帮助。您的第一句话说空列表的最小值是一个列表。
因此,
(fn(y,z)=>如果y
生成一个列表,并且y
和z
也必须是列表
对于空列表,您无法生成合理的值,因此您应该删除该情况并接受编译警告,或者引发异常。查找两个值中的最小值
表达式如果y
具有内置名称Int.min(y,z)
处理空名单
将空列表处理为minlist nil=nil
,这意味着“空整数列表中最小的整数就是空列表”。但空列表不是int,因此不能是int列表中的元素,也不能是返回最小int的函数的返回值
正如molbdnilo所说,您可以接受编译警告(如果您向函数提供空列表,则可能在运行时引发Match
异常),或者在给定空列表时引发特定异常,例如empty
。两者都不好,但后者至少能让问题变得清楚
在不使用foldr的情况下编写此文件可能看起来像:
fun minimum [] = raise Empty
| minimum [x] = x
| minimum (x::xs) = Int.min (x, minimum xs)
fun minimum [] = NONE
| minimum [x] = SOME x
| minimum (x::xs) =
case minimum xs of
NONE => SOME x
| SOME y => SOME (Int.min (x, y))
将递归函数转换为折叠函数
给定某个递归函数foo
,该函数依赖于某个函数bar
和某个默认值acc
:
fun foo [] = acc
| foo (x::xs) = bar (x, foo xs)
您可能会注意到minimum
和foo
之间的相似性:
是acc
,是一些最小值x
是bar
Int.min
最小值
递归方案的一次尝试
给定函数foldr:
fun foldr f e [] = e
| foldr f e (x::xs) = f (x, foldr f e xs);
fun minimum [] = ...
| minimum (x::xs) = foldr ...
您可能会注意到相同的相似之处:
是f
,但被制成一个参数条
是e
,但被制成一个参数acc
minimum
中唯一不适合此通用递归方案的是处理空列表。因此,您仍然必须将其与foldr
分开:
fun foldr f e [] = e
| foldr f e (x::xs) = f (x, foldr f e xs);
fun minimum [] = ...
| minimum (x::xs) = foldr ...
但其余的情况类似
错误感知返回类型
第三种选择是将函数的类型签名更改为
val minimum : int list -> int option
你目前的练习可能不允许这样做
在不使用foldr的情况下编写此文件可能看起来像:
fun minimum [] = raise Empty
| minimum [x] = x
| minimum (x::xs) = Int.min (x, minimum xs)
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 [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
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
由于在递归调用返回之前无法计算outerInt.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]
~> 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
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
而不是foldr
来解决此练习,方法与上面的方法完全相同,并且您将有一个使用较少堆栈空间的尾部递归变量