SML:如何将函数传递给列表并返回列表并删除所有负面实数?

时间:2013-01-17 18:51:20

标签: list recursion sml ml

这是我到目前为止所得到的......

fun positive l1 = positive(l1,[],[])
|   positive (l1, p, n) = 
       if hd(l1) < 0
         then positive(tl(l1), p, n @ [hd(l1])
       else if hd(l1) >= 0
         then positive(tl(l1), p @ [hd(l1)], n)
       else if null (h1(l1))
         then p

是的,这是出于教育目的。我正在大学学习ML课程,我们必须写一个程序,它将返回列表中的最大整数,我想要超越它,看看我是否也可以从中删除积极因素。

另外,如果可能的话,有人能指出我体面的ML书或入门书吗?我们的课文根本没有解释好。

2 个答案:

答案 0 :(得分:2)

您没有提到您的代码没有输入。

你的第一个函数子句只有变量l1,它在递归中使用。但是在这里它被用作三元组的第一个元素,它作为参数给出。这与SML使用的Hindley-Milner类型系统并不完全相同。以下非正式的想法可能会更好地看出这一点:

让我们假设l1的类型为'a,因此函数必须接受该类型的参数并返回未知的'a -> ...。但是,在右侧,您可以创建一个必须具有(l1, [], [])类型的参数'a * 'b list * 'c list。但由于它作为参数传递给函数,这也必然意味着'a等于'a * 'b list * 'c list,显然情况并非如此。

显然这不是你原来的意图。看来你的意图似乎是有一个以列表作为参数的函数,然后同时有一个递归的辅助函数,它需要两个额外的累积参数,即原始列表中的正数和负数列表。 / p>

为此,您至少需要为辅助函数指定另一个名称,这样它的定义就不会重新绑定原始函数的定义。 然后你有一些选项,关于这个辅助函数应该在哪个范围。一般来说,除了从“main”函数调用这个辅助函数没有任何意义,那么它不应该是一个位置范围在“主要”功能之外。这可以使用像这样的let绑定来完成:

fun positive xs = 
    let
      fun positive' ys p n = ...
    in
      positive' xs [] [] 
    end

这样,无法在positives'函数之外调用辅助函数positive

这样可以解决原始代码存在的一些问题。

  • 由于您只返回正整数列表,因此无需跟踪正整数 消极的。

  • 您应该使用模式匹配来分解列表元素。这样你就消除了 使用列表的头部和尾部,还需要验证是否存在 列表中的头尾。

    fun foo []      = ... (* input list is empty *)
      | foo (x::xs) = ... (* x is now the head, and xs is the tail *)
    
  • 您不应该使用追加运算符(@),只要您可以避免它(您总是可以)。 问题是当你左边有一个巨大的列表时,它的运行时间很糟糕 侧面和右侧的小清单(右侧通常是这种情况,如 它主要用于附加单个元素)。因此,它通常应该被认为是坏的 练习使用它。

    然而,存在一个非常简单的解决方案,即始终连接元素 在列表前面(以相反的顺序构建列表),然后只是反转列表 当它作为最后一件事(按预期顺序制作)返回时:

    fun foo [] acc = rev acc
      | foo (x::xs) acc = foo xs (x::acc)
    

鉴于这些小笔记,我们最终会得到一个看起来像这样的函数

fun positive xs =
    let
      fun positive' [] p = rev p
        | positive' (y::ys) p =
          if y < 0 then
            positive' ys p
          else
            positive' ys (y :: p)
    in
      positive' xs []
    end

答案 1 :(得分:1)

您是否了解过List.filter?这可能是合适的 - 它接受类型为'a -> bool的函数(它是谓词)和类型'a list的列表,并返回仅包含谓词求值为的元素的列表{ {1}}。例如:

true

您现有的代码无效,因为您使用的List.filter (fn x => Real.>= (x, 0.0)) [1.0, 4.5, ~3.4, 42.0, ~9.0] int与整数进行比较。代码<将在hd(l1) < 0列表中运行,而不是int列表。标准ML不会自动强制数字文字。必须明确写出real,并使用0.0进行测试。

如果您不想使用标准库中的Real.< (hd(l1), 0.0),可以考虑如何自己实现filter。这是一种方式:

filter