Functional programming ocaml嵌套列表中的递归
我是Ocaml新手,正在编写代码来替换嵌套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
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替换最后一行,它解决了我的问题