【问题标题】:Remove real element from list - SML从列表中删除真实元素 - SML
【发布时间】:2016-02-03 17:27:47
【问题描述】:

我写了以下代码:

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 ,但这些给我带来了错误。

有什么建议吗?

谢谢

【问题讨论】:

  • 您的函数(在 int 的情况下)只会从列表中删除 elem 的第一次出现——这是设计使然吗?此外——如果elem 不在列表中,即使列表本身可能不为空,您的函数也会引发Empty。也许你应该提出一个自定义错误。最后——除非这是家庭作业,否则使用库函数List.filter 更有意义。
  • 比较第一个,如果它与 elem 相同,则删除列表的第一个元素。这就是为什么 else 子句是 hd::remove_element(tl, elem) 所以列表的其他元素不会消失。
  • 我理解您定义的逻辑,但不确定是否仅删除第一次出现的 elem 是功能还是错误。对我来说,将 [2,1,3,4] 称为从 [2,3,1,3,4] 中删除 3 的结果似乎很奇怪,但这就是 remove_element([2,3,1,3,4], 3); 返回的结果。
  • @JohnColeman 是的,我知道,但我不认为我可以使用 List.filter 原因正如你所说,这是一项家庭作业,我无法集成功能。

标签: sml smlnj


【解决方案1】:

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

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

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

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

5) 我更多地利用了空白。部分是口味问题,但我认为相当复杂的子句(如您的第二行)应该分成多行。

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

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

返回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

【讨论】:

  • 非常感谢您的回答!
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2021-03-25
    • 2021-06-26
    • 1970-01-01
    • 1970-01-01
    • 2016-01-01
    • 1970-01-01
    • 2018-12-05
    • 2017-03-05
    相关资源
    最近更新 更多