Functional programming ocaml嵌套列表中的递归

Functional programming ocaml嵌套列表中的递归,functional-programming,ocaml,Functional Programming,Ocaml,我是Ocaml新手,正在编写代码来替换嵌套Ocaml列表中的元素。我的代码如下: type 'a sexp = S of 'a | L of 'a sexp list 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

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

    type 'a sexp = S of 'a | L of 'a sexp list
    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)
| L l :: t -> L (subst a b l) :: (subst a b t)
我的替换函数(它将嵌套列表中出现的所有元素a替换为b)如下所示:

    type 'a sexp = S of 'a | L of 'a sexp list
    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)
| L l :: t -> L (subst a b l) :: (subst a b t)

尽管多次尝试(将近6个小时),我还是无法编译这段代码。。请帮忙

您的函数
subst
应该返回sexp列表类型的内容。这就是第一个和第二个匹配案例返回的结果

在第三种匹配情况下,返回值为:

(subst a b l) :: (subst a b t)
因为您的函数返回一个sexp列表,所以这种类型没有多大意义。列表的头是一个sexp列表类型,列表的尾也是一个sexp列表类型。很难列出任何具有这种结构的列表。我想你想要的是名单的头是一个sexp类型


如果您希望列表的标题是
'a sexp
类型,则需要某种方式将一系列内容打包成一个单一的'
a sexp
。如果这还不够提示,请查看您的
L
构造函数。这正是它所做的。

看起来你的函数
subst
应该返回一个sexp列表类型的东西。这就是第一个和第二个匹配案例返回的结果

在第三种匹配情况下,返回值为:

(subst a b l) :: (subst a b t)
因为您的函数返回一个sexp列表,所以这种类型没有多大意义。列表的头是一个sexp列表类型,列表的尾也是一个sexp列表类型。很难列出任何具有这种结构的列表。我想你想要的是名单的头是一个sexp类型


如果您希望列表的标题是
'a sexp
类型,则需要某种方式将一系列内容打包成一个单一的'
a sexp
。如果这还不够提示,请查看您的
L
构造函数。这正是它所做的。

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

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

    type 'a sexp = S of 'a | L of 'a sexp list
    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)
| 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
返回一个Sexp列表
。如果省略最后一行中的
L
构造函数,则
subst a b L
的类型为
'a Sexp list
,您试图将其与另一个类型为
'a Sexp list
的列表进行对比。这是行不通的


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

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

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

    type 'a sexp = S of 'a | L of 'a sexp list
    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)
| 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
返回一个Sexp列表
。如果省略最后一行中的
L
构造函数,则
subst a b L
的类型为
'a Sexp list
,您试图将其与另一个类型为
'a Sexp list
的列表进行对比。这是行不通的


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

我可以建议您先编写一个类型为
'a->'a->'a Sexp->'a Sexp
的函数
subst
?它会读

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
s的函数,您可以轻松定义
'a->'a->'a->'a sexp list->'a sexp list
类型的函数
subst\u list

let subst_list x y sexps = List.map (subst x y) sexps
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

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

let map f sexp =
  let rec visit = function
    | S x -> S (f x)
    | L sexps -> L (List.map visit sexps)
  in
  visit sexp
然后按照
map
subst\u list
定义
subst
,与前面一样,按照
subst

let subst_list x y sexps = List.map (subst x y) sexps
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

我是否可以建议先编写类型为
'a->'a->'a sexp->'a sexp
的函数
subst
?它会读

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
s的函数,您可以轻松定义
'a->'a->'a->'a sexp list->'a sexp list
类型的函数
subst\u list

let subst_list x y sexps = List.map (subst x y) sexps
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

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

let map f sexp =
  let rec visit = function
    | S x -> S (f x)
    | L sexps -> L (List.map visit sexps)
  in
  visit sexp
然后按照
map
subst\u list
定义
subst
,与前面一样,按照
subst

let subst_list x y sexps = List.map (subst x y) sexps
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

试着用
|L::t->L(subst a b L)::(subst a b t)
@shreaderoy替换最后一行,它解决了我的问题