这是我到目前为止所得到的......
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书或入门书吗?我们的课文根本没有解释好。
答案 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