通过函数签名递归解压缩列表

时间:2011-09-03 20:52:01

标签: sml

我正在尝试在sml中编写一个函数,它“解包”任意深度的嵌套列表。例如,unpack [[[1,2]]]应该产生[1,2]。我正在尝试类似的事情:

有趣解包xs = if nestedp(xs)然后解压(hd xs)其他xs;

与 有趣的nestedp [_] =真   | nestedp _ = false;

sml不喜欢以这种方式定义unpack,因为它将unpack的类型推断为'a list - > '一个 。对hd的调用的返回被传递回unpack,但它现在不会“看到”列表而是单个变量。

是否有可能以这种方式解压缩嵌套列表?

1 个答案:

答案 0 :(得分:1)

您不能对内置列表类型执行此操作,因为您无法使类型匹配。

例如,有人可能认为使用类型'a list list -> 'a list的函数是可能的,然后递归地应用它,直到它到达非嵌套列表的基本情况。但是,您无法以任何方式检测基本情况,从而使您的类型不匹配。

但是,如果您创建了自己的列表类型,则可以这样做:

datatype 'a nestableList = Cons of 'a * 'a nestableList
                         | NCons of 'a nestableList * 'a nestableList
                         | Nil;

此处,ConsNil::[]的工作方式相同,而NCons则允许嵌套列表构建。

举个例子:

(* The list [[1, 2], [[3], [4, 5, 6]]] *)
val nlist = NCons(
              Cons(1, Cons(2, Nil)),
              NCons(
                NCons(
                  Cons(3, Nil),
                  Cons(4, Cons(5, Cons(6, Nil)))
                ),
                Nil
              )
           );

然后你可以像这样展平这个嵌套列表类型:

fun flatten nls =
let
  fun flatten_ Nil                 = []
    | flatten_ (NCons(head, tail)) = flatten head @ flatten tail
    | flatten_ ( Cons(head, tail)) = head :: flatten tail
in
    flatten_ nls
end;

然后可以像这样使用

val flattenedNlist = flatten nlist;     (* Yields [1, 2, 3, 4, 5, 6] *)

这里我得到了一个常规列表,但可以很容易地改变它来返回相同类型的列表。