所以我有一个stmt
(代数类型)列表,列表中包含许多VarDecl
。
我想将列表从stmt list
缩减为VarDecl list
。
当我使用List.filter
时,我可以删除所有其他类型,但我仍然留下stmt list
。
我发现我能够通过折叠进行过滤以及类型更改,但我无法弄清楚如何概括它(我需要在项目中的许多地方使用此模式)。
let decls = List.fold_left
(fun lst st -> match st with
| VarDecl(vd) -> vd :: lst
| _ -> lst
) [] stmts in
是否有更好的方法来执行过滤器并转换为列表类型的变体?
答案 0 :(得分:1)
您可以使用GADT或多态变体,但两者都会增加复杂性。
这里有一个粗略的草图,说明如何使用多态变体解决这个问题:
type constant = [ `Int of int | `String of string ]
type var = [ `Var of string ]
type term = [ constant | var | `Add of term * term ]
let rec select_vars (list : term list) : var list =
match list with
| [] -> []
| (#var as v)::list -> v::select_vars list
| _::list -> select_vars list
let rec select_constants (list : term list) : constant list =
match list with
| [] -> []
| (#constant as k)::list -> k::select_constants list
| _::list -> select_constants list
另一种可能性是将var
的位拉出为可以列出的显式类型:
type var = {
...
}
type term =
| Int of int
| Var of var
这有一些开销,因为这些位只是构造函数args,而var
不是term
,所以你可能需要做一些包装和解包。
答案 1 :(得分:1)
假设您有类似
的类型type stmt = VarDecl of int | Foo of int | Bar | Fie of string
和stmt列表,Batteries让你做
let vardecl_ints l =
List.filter_map (function Vardecl i -> Some i | _ -> None) l
let foo_ints l =
List.filter_map (function Foo i -> Some i | _ -> None) l
我认为这是简明扼要的。我不 认为你可以为ADT制作一般的“列表获取者”,例如。
let bars l =
List.filter_map (function Bar -> Some Bar | _ -> None) l
https://github.com/ocaml-batteries-team/batteries-included/blob/master/src/batList.mlv#L456
如果你不想要的话,有电池实现的filter_map
依赖。使用[]而不是Acc的功能版本将非常相似,只是这样做
(x :: dst)和最后的|>List.rev
。
答案 2 :(得分:0)
如果没有看到您的类型定义(或简化版本),很难回答。
但请注意,如果您有这个定义:
type xyz = X | Y | Z
值X,Y和Z不是类型。他们的价值观。可能Vardecl也是一个值。因此,您无法获得该类型的列表(在OCaml中)。
<强>更新强>
我为这种情况做的一件事是使用从你想要的一个变体投射的类型:
type xyz = X | Y of int * int | Z
let extract_proj v l =
match v with
| X | Z -> l
| Y (a, b) -> (a, b) :: l
let filter_to_y l =
List.fold_right extract_proj l []
这是一个顶级会议:
type xyz = X | Y of int * int | Z
val extract_proj : xyz -> (int * int) list -> (int * int) list = <fun>
val filter_to_y : xyz list -> (int * int) list = <fun>
# filter_to_y [X; Z; Y(3,4); Z; Y(4,5)];;
- : (int * int) list = [(3, 4); (4, 5)]