从 OCaml 语法中删除无法访问的规则
我是 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))
I'm new to Ocaml and for a homework assignment I have to write a function filter_reachable
that takes a grammar and returns a reduced grammar with the unreachable rules removed. The only modules I'm allowed to use are Pervasives and List modules and no other modules.
The idea I have is to first make a list of all reachable nonterminals. Then a rule is reachable if it's nonterminal part is in the list of all reachable nonterminals. All the rules that are reachable then placed into a new list and paired with the start symbol to create the reduced grammar.
My solution is below. However it doesn't work and I don't understand why. Can anyone help me fix it?
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))
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
想象一下对
fil (st, rl)
的倒数第二次递归调用。在此调用中,rl
仅包含一条规则。您的代码将尝试通过查看这一规则来发现规则的非终结符是否可达。除非非终结符是开始符号,否则这是行不通的。一般来说,我想说你必须携带更多的背景信息。我不想透露太多,但这基本上是一个经典的有向图遍历问题。每个语法规则都是图中的一个节点。边从规则 R 延伸到定义出现在 R 的 RHS 中的非终结符的其他规则。这种著名的图遍历算法通常适用于“已访问”节点的列表。您需要这个,因为图表可以有循环。
这是一个带有循环的语法:
Imagine the second last recursive call to
fil (st, rl)
. In this callrl
has just one rule in it. Your code is going to try to discover whether the nonterminal of the rule is reachable by just looking at this one rule. This isn't going to work unless the nonterminal is the start symbol.Generally speaking I'd say you have to carry around quite a bit more context. I don't want to give too much away, but this is basically a classic directed graph traversal problem. Each grammar rule is a node in the graph. Edges go from a rule R to the other rules defining the nonterminals that appear in the RHS of R. This famous graph traversal algorithm generally works with a list of "visited" nodes. You need this because the graph can have cycles.
Here is a grammar with cycles:
关于您的代码的一些注释:
您可以使用
List.mem
get_nont
中的模式匹配可以组合:在函数式编程中,柯里化用于定义具有多个参数的函数。请参阅范围、柯里化和列表,“柯里化”部分函数”。
使用模式匹配的力量,例如,为
get_rea_nont
演示的:尝试模块化您的代码,例如针对
get_rea_nont
:n
(请参阅List.filter
)。get_nont
(请参阅List.map
)List.flatten
得到预期的结果。因此,...
Some remarks on your code:
Instead of
member
, you could useList.mem
The pattern matching in
get_nont
can be combined:In functional programming, currying is used to define functions with more than one argument. See Scope, Currying, and Lists,section "Curried functions".
Use the power of pattern matching, e.g., demonstrated for
get_rea_nont
:Try modularize your code, e.g., for
get_rea_nont
:n
(seeList.filter
).get_nont
(seeList.map
)List.flatten
to get the expected result.Thus, ...