从列表中删除真实元素 - 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<=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) 我将其更改为从列表中删除所有出现的元素,而不仅仅是第一次出现的元素。这涉及将基本情况更改为 returning 空列表,因为删除 y
的 []
只是 []
而不是错误情况。此外,如果找到元素,我 return 不是简单地 returning 尾部,而是将递归调用应用于尾部以删除以后出现的任何其他事件。您可以轻松修改代码,使其更接近您的原始代码。
2) 我需要放置显式类型注释 x:real
,以便 SML 可以推断列表的类型为 real list
而不是类型 int list
。
3) 出于美观原因,我将 nil
替换为 []
4) 我用 y::ys
替换了你的模式 hd::tl
。一方面,hd
和 tl
是内置函数——我认为没有理由将这些标识符绑定到其他任何东西,即使它只是函数定义的本地函数。另一方面,图案中的视觉混乱越少越好。
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
我写了下面的代码:
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<=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) 我将其更改为从列表中删除所有出现的元素,而不仅仅是第一次出现的元素。这涉及将基本情况更改为 returning 空列表,因为删除 y
的 []
只是 []
而不是错误情况。此外,如果找到元素,我 return 不是简单地 returning 尾部,而是将递归调用应用于尾部以删除以后出现的任何其他事件。您可以轻松修改代码,使其更接近您的原始代码。
2) 我需要放置显式类型注释 x:real
,以便 SML 可以推断列表的类型为 real list
而不是类型 int list
。
3) 出于美观原因,我将 nil
替换为 []
4) 我用 y::ys
替换了你的模式 hd::tl
。一方面,hd
和 tl
是内置函数——我认为没有理由将这些标识符绑定到其他任何东西,即使它只是函数定义的本地函数。另一方面,图案中的视觉混乱越少越好。
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