2

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

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 课,我们必须编写一个程序来返回列表中的最大整数,我想超越它,看看我是否也可以从中删除积极因素。

另外,如果可能的话,谁能指点我一本像样的机器学习书籍或入门书?我们的课文根本没有很好地解释事情。

4

2 回答 2

2

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

您的第一个函数子句只有变量l1,用于递归。然而在这里它被用作三元组的第一个元素,作为参数给出。这与 SML 使用的 Hindley-Milner 类型系统并不真正齐头并进。以下非正式想法可能会更好地说明这一点:

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

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

为此,您至少需要为您的辅助函数指定另一个名称,这样它的定义就不会重新绑定原始函数的定义。然后你有一些选项,关于这个辅助函数应该在哪个范围内。一般来说,如果除了从“主”函数调用这个辅助函数没有任何意义,那么它不应该放在“主要”功能之外的范围。这可以使用这样的 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
于 2013-01-18T00:51:51.400 回答
1

你了解过List.filter吗?这里可能是合适的——它接受一个类型的函数(它是一个谓词)'a -> bool和一个类型的列表'a list,并返回一个列表,该列表仅由谓词计算为的元素组成true。例如:

List.filter (fn x => Real.>= (x, 0.0)) [1.0, 4.5, ~3.4, 42.0, ~9.0]

您现有的代码将不起作用,因为您正在int使用<. 该代码hd(l1) < 0将适用于 列表int,而不是real. 标准 ML 不会自动强制数字文字。必须明确编写0.0, 并Real.< (hd(l1), 0.0)用于您的测试。

如果您不想filter从标准库中使用,您可以考虑如何实现filter自己。这是一种方法:

fun filter f [] = []
  | filter f (h::t) =
      if f h 
      then h :: filter f t 
      else filter f t
于 2013-01-17T22:04:04.217 回答