我写了以下代码:
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。我需要让它适用于实数,但我无法做到。我已经尝试了很多方法来重写函数,我也使用过:真实但这些都给我带来了错误。
有什么建议吗?
谢谢
答案 0 :(得分:2)
问题在于:hd=elem
在ML和Javascript等语言中,您无法直接比较两个实数,因为实数必然会出现舍入错误。
您必须使用lambda范围并定义间隔。 elem - lambda < hd andalso elem + lambda > hd
答案 1 :(得分:2)
接受的答案应该允许您完成作业,因此我将展示另外两种方法来解决您的问题,而不必担心为您做作业。正如凯文约翰逊所说,直接比较两个实际是不可能的。当且仅当a=b
和a<=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::ys
和hd
是内置函数 - 我认为没有理由将这些标识符绑定到任何其他标识符,即使它只是函数定义的本地标识符。另一方面,模式中的视觉混乱越少越好。
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);