ocaml嵌套列表中的递归

时间:2013-06-05 18:05:20

标签: functional-programming ocaml

我是Ocaml的新手,我正在编写代码来替换嵌套的Ocaml列表中的元素。我的代码如下:

    type 'a sexp = S of 'a | L of 'a sexp list

我的替换函数(它替换了嵌套列表中所有出现的元素a和b)如下:

    let rec subst a b list = match list with
    | [] -> list
    | S s :: t -> if s = a then (S b) :: (subst a b t) else (S s) :: (subst a b t)
    | L l :: t -> (subst a b l) :: (subst a b t)

尽管多次尝试(近6个小时),但我还是无法编译此代码..请帮忙!

3 个答案:

答案 0 :(得分:3)

我可以建议先写一个subst类型的函数'a -> 'a -> 'a sexp -> 'a sexp吗?它会读

let subst x y sexp =
  let rec visit = function
    | S z -> S (if z = x then y else z)
    | L sexps -> L (List.map visit sexps)
  in
  visit sexp

并且很好地和惯用地捕获了在sexp上递归的想法。

现在,要获得一个对列表而不是单个sexp进行操作的函数,您可以轻松定义subst_list类型的函数'a -> 'a -> 'a sexp list -> 'a sexp list

let subst_list x y sexps = List.map (subst x y) sexps

更好的是从抽象中抽象出来,并使用类型为map的更普遍适用的函数('a -> 'b) -> 'a sexp -> 'b sexp来执行sexp s的结构保留映射:

let map f sexp =
  let rec visit = function
    | S x -> S (f x)
    | L sexps -> L (List.map visit sexps)
  in
  visit sexp

然后按照substmap的方式定义subst_list,与subst一样:

let subst x y sexp = map (fun z -> if z = x then y else z) sexp
let subst_list x y sexps = List.map (subst x y) sexps

答案 1 :(得分:2)

注意:在这里使用F#编译器;我这台计算机上没有OCaml编译器。

subst函数的最后一行有错误:它应该如下:

| L l :: t -> L (subst a b l) :: (subst a b t)

所以完整的代码看起来像这样:

type 'a Sexp =
    | S of 'a
    | L of 'a Sexp list

let rec subst (a) (b) (lst : 'a Sexp list) =
    match lst with
    | [] -> lst
    | S s :: t -> if s = a then (S b) :: (subst a b t) else (S s) :: (subst a b t)
    | L l :: t -> L (subst a b l) :: (subst a b t)

let test () =
    let (lst : int Sexp list) = [S 1; L [S 2; L [S 3]; S 4]; S 5]
    let a = 2
    let b = 3
    subst a b lst

test()的输出是

[S 1; L [S 3; L [S 3]; S 4]; S 5]

原因是您的函数subst返回'a Sexp list。如果您忽略了最后一行的L构造函数,那么subst a b l的类型为'a Sexp list,您试图将其与另一个类型为'a Sexp list的列表合并。这不起作用。

这也不是您的意图,因为您希望最终得到'a Sexp list类型的实体,这意味着您必须使用类型为'a Sexp的列表来构建'a Sexp list类型的元素。通过指定L构造函数,您将创建一个'a Sexp list类型的元素,现在可以将其与列表的其余部分一起使用。

答案 2 :(得分:1)

看起来你的函数subst应该返回'a sexp list类型的东西。这就是第一和第二场比赛的回归。

在第三个匹配的情况下,您的返回值为:

(subst a b l) :: (subst a b t)

由于您的函数返回'a sexp list,因此这种类型没有多大意义。列表的头部是'a sexp list类型,列表的尾部是类型'a sexp list。提出具有这种结构的任何列表是非常困难的。我想你想要的是列表的头部是'a sexp类型。

如果您希望列表的头部属于'a sexp类型,则需要某种方法将一系列内容打包成一个单独的a sexp。如果这还不够,请查看您的L构造函数。这正是它的作用。