我正在尝试在sml中编写一个函数,该函数将列表作为其第一个参数,将数字作为其第二个参数。结果应该是:greaterT [3,5,2,4,7] 3; val it = [5,4,7]:int list
到目前为止,这是我的工作,但还没有成功。
fun greaterT ([],k) = []
| greaterT (a::x,k)
if a <= k
then x = []
else greaterT(x,k);
答案 0 :(得分:0)
您遇到问题是因为then
表达式的if
分支正试图做一些没有意义的事情:
x = []
您无法在标准ML中为已绑定的标识符重新分配值,但您可以使用ref
s实现可变性,但在这种情况下不需要它们。
在您的情况下,所需功能在概念上的作用是查看列表的第一个元素,通过将其与k
进行比较来决定是否将其保留在最终结果中,然后对其余部分进行递归列表:
fun greaterT ([], k) = []
| greaterT (a :: rest, k) =
if a <= k then
a :: greaterT (rest, k)
else
greaterT (rest, k)
上面不是一个好的解决方案,因为第一个递归调用不在尾部位置,因此编译器无法优化生成的代码(出于我赢得的原因,#39;在这里讨论;有很多questions about tail-call optimizations on StackOverflow)。
因此,更好的版本会使用额外的参数来累积满足<=
谓词的元素。
fun greaterTailRec ([], k, result) = List.rev result
| greaterTailRec (a :: rest, k) =
if a <= k then
greaterTailRec (rest, k, result)
else
greaterTailRec (rest, k, a :: result)
fun greaterT (list, k) = greaterTailRec (list, k, [])
我们可以更进一步,通过将特定内容(在此特定情况下是比较调用greaterTailRec
)替换为对函数的更一般调用来概括<=
。列为参数并返回bool
。因此,我们最终会得到一个名为filter
的通用函数:
fun filter predicate list =
let
fun recur ([], result) = List.rev result
| recur (a :: rest, result) =
if predicate a then
recur (rest, a :: result)
else
recur (rest, result)
in
recur (list, [])
end
fun greaterT (list, k) =
filter (fn a => a >= k) list
filter
helper function已定义List
structure,因此您的初始函数可以更简洁地表达为:
fun greaterT (list, k) =
List.filter (fn a => a >= k) list