从列表中删除真实元素 - SML

Remove real element from list - SML

我写了下面的代码:

fun remove_element(nil, elem) = raise Empty
  | remove_element(hd::tl, elem) = if(hd=elem) then tl else hd::remove_element(tl, elem);

但该函数(从列表中删除元素 elem)适用于 int。我需要让它适用于实数,但我做不到。我尝试了很多重写函数的方法,我也使用了 :real 但是这些给我带来了错误。

有什么建议吗?

谢谢

问题在这里:hd=elem 在 ML 和 Javascript 等语言中,您不能直接比较两个实数,因为实数必然会出现舍入误差。 您必须使用 lambda 范围并定义一个间隔。 elem - lambda < hd andalso elem + lambda > hd

接受的答案应该可以让您完成作业,因此我将展示其他两种方法来解决您的问题变体,而不必担心为您做功课。正如凯文约翰逊所说,直接比较两个实数是不可能的。可以间接地这样做,因为 a=b 当且仅当 a<=bb<=a。这通常是一个错误,尤其是当所讨论的列表是由数值计算产生的数字时。但是 - 在某些情况下比较实数以获得平等是有意义的,所以只要您清楚这就是您想要的,您当然应该能够这样做。这导致对您的代码进行以下修改:

fun remove_real([],x:real) = []
|   remove_real(y::ys,x) =
        if (y <= x andalso y >= x) then
            remove_real(ys,x)
        else
            y::remove_real(ys,x);

几点:

1) 我将其更改为从列表中删除所有出现的元素,而不仅仅是第一次出现的元素。这涉及将基本情况更改为 returning 空列表,因为删除 y[] 只是 [] 而不是错误情况。此外,如果找到元素,我 return 不是简单地 returning 尾部,而是将递归调用应用于尾部以删除以后出现的任何其他事件。您可以轻松修改代码,使其更接近您的原始代码。

2) 我需要放置显式类型注释 x:real,以便 SML 可以推断列表的类型为 real list 而不是类型 int list

3) 出于美观原因,我将 nil 替换为 []

4) 我用 y::ys 替换了你的模式 hd::tl。一方面,hdtl 是内置函数——我认为没有理由将这些标识符绑定到其他任何东西,即使它只是函数定义的本地函数。另一方面,图案中的视觉混乱越少越好。

5) 我更多地使用了白色space。部分是个人喜好问题,但我认为相当复杂的子句(比如你的第二行)应该分成多行。

如果您想采用包含误差容限的方式来比较实数,我认为将容差作为显式参数包含在内是最有意义的。我发现 |x-y| < e 比两个不等式更自然。不幸的是,内置 abs 仅适用于整数。如果 x - y 是实数,则表达式

if x - y < 0.0 then y - x else x - y

returns是x - y的绝对值(负号翻转符号)。作为额外的好处——与 0.0 而不是 0 的比较是 SML 推断类型所需的全部。这导致:

fun remove_elem([],x,tol) = []
|   remove_elem(y::ys,x,tol) =
        if (if x - y < 0.0 then y - x else x - y) < tol then
            remove_elem(ys,x,tol)
        else
            y::remove_elem(ys,x,tol);

典型输出:

- remove_real([2.0, 3.1, 3.14, 3.145, 3.14], 3.14);
val it = [2.0,3.1,3.145] : real list

- remove_elem([2.0, 3.1, 3.14, 3.145, 3.14], 3.14,0.01);
val it = [2.0,3.1] : real list

- remove_elem([2.0, 3.1, 3.14, 3.145, 3.14], 3.14,0.001);
val it = [2.0,3.1,3.145] : real list