SML:如何将列表分配到子列表

时间:2016-03-20 09:56:00

标签: sml

我从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 *)

这个问题确实困扰了我。

1 个答案:

答案 0 :(得分:3)

假设这是家庭作业,我不愿给出完整的答案,但这里有一些提示:

1)在空基础案例中,我认为您想要返回[[]]而不是[]。你的规范没有解决这个问题,但由于空列表最长的非减少整数列表,可以从空列表的前面拉出,返回值应该是由空列表。这有点类似于空集的powerset(所有子集的集合)是包含空集而不是空集本身的集合的事实。你应该如何定义这个特殊情况并不重要,因为真实的基础是......

2)在[x]情况下,您确实需要返回[[x]]而不是[x],因为您尝试编写的函数类型为int list -> int list list

3)在剩下的情况下,您可以编写类似

的模式
|    split (x::y::zs) = (* fill this in *)

然后测试x <= y是否决定做什么。由于x <= yx > 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