【问题标题】:Trying to write a function in SML尝试在 SML 中编写函数
【发布时间】:2015-03-12 23:03:48
【问题描述】:

我正在尝试在 sml 中编写一个函数,该函数将一个列表作为其第一个参数,将一个数字作为其第二个参数。结果应该是:greaterT [3,5,2,4,7]3; val it = [5,4,7] : int 列表

这是我目前的工作,但还没有工作。

fun greaterT ([],k) = []
|   greaterT (a::x,k)
if a <= k
then x = [] 
else greaterT(x,k);

【问题讨论】:

  • 不起作用到底是什么意思?
  • 在新泽西州的 SML 中运行时出现错误,错误类型的 if 分支不同意 then 分支:bool else 分支:表达式中的 Z 列表 if a

标签: logic sml


【解决方案1】:

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

x = []

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

在您的情况下,所需函数在概念上的作用是查看列表的第一个元素,通过将其与 k 进行比较来决定是否将其保留在最终结果中,然后对列表的其余部分进行递归:

fun greaterT ([], k) = []
  | greaterT (a :: rest, k) =
      if a <= k then
        a :: greaterT (rest, k)
      else
        greaterT (rest, k)

不过,上面不是一个好的解决方案,因为第一个递归调用不在尾部位置,所以编译器无法优化生成的代码(原因我在这里不讨论;有很多questions about tail-call optimizations on StackOverflow)。

因此,更好的版本会使用一个额外的参数,它会在其中累积满足&lt;= 谓词的元素。

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 泛化,将具体情况(在这种特殊情况下是比较调用&lt;=)替换为对将列表元素作为参数的函数的更一般调用,并返回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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-10
    • 1970-01-01
    • 2019-08-31
    • 1970-01-01
    • 1970-01-01
    • 2013-12-29
    相关资源
    最近更新 更多