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

时间:2015-11-03 14:08:06

标签: sml smlnj

我写了以下代码:

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。我需要让它适用于实数,但我无法做到。我已经尝试了很多方法来重写函数,我也使用过:真实但这些都给我带来了错误。

有什么建议吗?

谢谢

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:2)

接受的答案应该允许您完成作业,因此我将展示另外两种方法来解决您的问题,而不必担心为您做作业。正如凯文约翰逊所说,直接比较两个实际是不可能的。当且仅当a=ba<=b时,b<=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)我更改了它以从列表中删除所有出现的元素,而不仅仅是第一次出现。这涉及将基础案例更改为返回空列表,因为移除了[]的{​​{1}}只是y而不是错误情况。此外,如果找到元素,不是简单地返回尾部,而是返回应用于尾部的递归调用,以便稍后删除任何其他事件。您可以轻松修改代码,使其更接近原始代码。

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

3)出于审美原因,我将int list替换为nil

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

5)我更多地使用了空白区域。部分是品味问题,但我认为相当复杂的条款(如你的第二行)应该分成多行。

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

x - y

返回if x - y < 0.0 then y - x else x - y 的绝对值(如果它是负片的话,它会翻转符号)。作为一个额外的好处 - 与0.0而不是0的比较是SML需要推断出的类型。这导致:

x - y

典型输出:

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);