我是Ocaml的新手,为了完成家庭作业,我必须编写一个函数filter_reachable 采用语法并返回减少的语法,删除无法访问的规则。我唯一允许使用的模块是Pervasives和List模块,没有其他模块。
我的想法是首先列出所有可到达的非终结符。如果规则是非终端部分在所有可到达的非终端列表中,则可以到达规则。所有可到达的规则然后放入新列表并与开始符号配对以创建简化语法。
我的解决方案如下。但它不起作用,我不明白为什么。任何人都可以帮我解决这个问题吗?
let rec member x s=
match s with
[]->false
| y::ys-> (x = y) || member x ys
(*the type of a symbol*)
type ('nonterminal, 'terminal) symbol =
| N of 'nonterminal
| T of 'terminal
let rec get_nont sl=
match sl with
|[]->[]
|h::t->match h with
|N x-> x::get_nont t
|T y-> get_nont t
let rec get_rea_nont (n,r) =
n::(match r with
|[]->[]
|h::t->match h with
| a,b -> if a=n then (get_nont b)@(get_rea_nont (n,t))
else get_rea_nont(n,t)
| _-> [])
let rec fil (st,rl)=
let x = get_rea_nont(st,rl) in
(match rl with
|[]-> []
|h::t-> match h with
|a,b -> if (member a x) then h::fil(st,t)
else fil(st,t)
|_->[]
|_->[]
)
let rec filter(st,rl)=
(st,fil(st,rl))
答案 0 :(得分:3)
想象一下对fil (st, rl)
的第二次递归调用。在此次通话中,rl
只有一条规则。您的代码将尝试通过查看此规则来发现是否可以访问规则的非终结符。除非非终结符号是起始符号,否则这不会起作用。
一般来说,我会说你必须携带更多的背景。我不想放弃太多,但这基本上是一个经典的有向图遍历问题。每个语法规则是图中的一个节点。边缘从规则R转到定义出现在R的RHS中的非终结符的其他规则。这种着名的图遍历算法通常与“已访问”节点列表一起使用。你需要这个,因为图表可以有周期。
这是一个带循环的语法:
A ::= B | B '+' A
B :: = 'x' | 'y' | '(' A ')'
答案 1 :(得分:1)
对您的代码的一些评论:
您可以使用List.mem
member
。
get_nont
中的模式匹配可以合并:
let rec get_nont sl = match sl with
| [] -> []
| N x :: tl -> x :: get_nont tl
| T _ :: tl -> get_nont tl;;
在函数式编程中,currying用于定义具有多个参数的函数。请参阅Scope, Currying, and Lists,“Curried functions”部分。
使用模式匹配的力量,例如,为get_rea_nont
:
let rec get_rea_nont_old n r = n :: (match r with
| []->[]
| (a, b) :: t when a = n -> (get_nont b) @ (get_rea_nont_old n t)
| _ :: t -> get_rea_nont_old n t
);;
尝试模块化您的代码,例如get_rea_nont
:
n
(参见List.filter
)。 get_nont
(请参阅List.map
)List.flatten
以获得预期结果。因此,......
let get_rea_nont n r =
let filtered = List.filter (fun (a, _) -> a = n) r in
let nonterminals = List.map (fun (_, b) -> get_nont b) filtered in
n :: (List.flatten nonterminals);;