我从CS 217找到了这个问题。
将列表划分为一个或多个子列表,以便每个子列表包含非递减(排序)顺序的整数。
[3,5,1,8,9,2,1,0]返回[[3,5],[1,8,9],[2],[1],[0]]
[1,2,3,4,5,6]返回[[1,2,3,4,5,6]]
[5,4,3,2,1]返回[[5],[4],[3],[2],[1]]
以下代码有效:
val Q1 = [ 3, 5, 1, 8, 9, 2, 1, 0 ]
val A1 = foldl (
fn (x, a) =>
if x > hd (hd a) then (x::hd a)::tl a
else [x]::a
) [ [ hd Q1 ] ] (tl Q1)
val A1 = map rev (rev A1)
或者像这样:使用2个临时列表来收集。
fun split l = let
fun split' tmp subset =
fn [] => []
| [x] => (x::tmp)::subset
| (a::(c as b::_)) =>
if a < b then split' (a::tmp) subset c
else split' [] ((a::tmp)::subset) c
in (rev o map rev) (split' [] [] l) end
这个问题的解决方案很多, 但我仍然想知道如何将其编码为模式匹配函数? 可能类似下面的内容:
(不确定是否可能?)
fun split [] = [[]]
| split [x] = [[x]]
| split [a, b] = if a < b then (* here *) else (* here *)
| split (a::b) = if a < hd b then (* here *) else (* here *)
这个问题确实困扰了我。
答案 0 :(得分:3)
假设这是家庭作业,我不愿给出完整的答案,但这里有一些提示:
1)在空基础案例中,我认为您想要返回[[]]
而不是[]
。你的规范没有解决这个问题,但由于空列表是最长的非减少整数列表,可以从空列表的前面拉出,返回值应该是由空列表。这有点类似于空集的powerset(所有子集的集合)是包含空集而不是空集本身的集合的事实。你应该如何定义这个特殊情况并不重要,因为真实的基础是......
2)在[x]
情况下,您确实需要返回[[x]]
而不是[x]
,因为您尝试编写的函数类型为int list -> int list list
3)在剩下的情况下,您可以编写类似
的模式| split (x::y::zs) = (* fill this in *)
然后测试x <= y
是否决定做什么。由于x <= y
和x > y
都涉及split (y::zs)
,您可以计算一次,在let
绑定中为此命名,并且if
的范围为hd
这种约束,虽然这主要是品味问题。
请注意该模式在最后一种情况下的工作原理。在使用模式匹配的函数定义中显式使用let
应该是相当罕见的(尽管如果你在不使用模式匹配if
绑定的情况下充实最后一种情况,你将被迫使用它fun split [] = [[]]
| split [x] = [[x]]
| split (x::y::zs) =
let val first::rest = split (y::zs) in
if x <= y then
(x::first) :: rest
else
[x]::first::rest
end;
)中至少有一个分支。
On Edit:由于这不是家庭作业,这里有一个完整的实现:
TypeInfo