ocaml 嵌套列表中的递归

问题描述 投票:0回答:3

我是 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个小时),我还是无法编译此代码..请帮忙!

functional-programming ocaml
3个回答
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

然后用

subst
map
来定义
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

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
类型的元素,您现在可以将其与列表的其余部分结合使用。


1
投票

看起来你的函数

subst
应该返回
'a sexp list
类型的内容。这就是第一个和第二个匹配案例返回的内容。

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

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

由于您的函数返回

'a sexp list
,因此这种类型没有多大意义。列表头的类型为
'a sexp list
,列表尾部的类型为 'a sexp list
also
。很难想出任何具有这种结构的列表。我认为你想要的是列表的头部是
'a sexp
类型。

如果您希望列表的头部为

'a sexp
类型,则需要某种方法将事物列表打包为单个“
a sexp
”。如果这还不够提示,请查看您的
L
构造函数。这正是它的作用。

© www.soinside.com 2019 - 2024. All rights reserved.