试图用SML编写一个函数

时间:2015-03-12 13:17:10

标签: logic sml

我正在尝试在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);

1 个答案:

答案 0 :(得分:0)

您遇到问题是因为then表达式的if分支正试图做一些没有意义的事情:

x = []

您无法在标准ML中为已绑定的标识符重新分配值,但您可以使用refs实现可变性,但在这种情况下不需要它们。

在您的情况下,所需功能在概念上的作用是查看列表的第一个元素,通过将其与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