很多Prolog-in-Scheme实施都在那里.例如Kanren,Schelog.
显然,在"AI编程的范例"中,Norvig在Lisp中实现了Prolog-to-Lisp编译器,以便使用Definite Clause Grammars.
但是有更简单的清洁方式吗?也许一些聪明的使用amb来避免实施完整的"Prolog"?在Scheme中进行基于DCG的解析的最简单方法是什么?
我正在尝试构建一个识别所有符合此形式的列表的DCG : a^n b^2m c^2m d^n
.
我写了以下规则:
s --> [].
s --> ad.
ad --> a, ad, d.
ad --> bc.
bc --> b, b, bc, c, c.
bc --> [].
a --> [a].
b --> [b].
c --> [c].
d --> [d].
当我尝试评估具有这些规范的字符串时,如列表[a,b,b,c,c,d]
,它可以工作.但是当我尝试评估查询phrase(s, X)
以便我可以看到这个语法返回的所有可能的字符串时,它会循环到无穷大.
我构建DCG的方式有问题吗?
我有这个代码将整数转换为罗马数字我需要添加一个函数,将整数与罗马数字输入进行比较,并显示它是否为try或false,例如:roman(v,5).真正
toroman(0).
toroman(N) :- N < 4, put("I"), M is N - 1, toroman(M).
toroman(N) :- N = 4, put("I"), put("V").
toroman(N) :- N = 5, put("V").
toroman(N) :- N < 9, put("V"), M is N - 5, toroman(M).
toroman(N) :- N = 9, put("I"), put("X").
toroman(N) :- N < 40, put("X"), M is N - 10, toroman(M).
toroman(N) :- N < 50, put("X"), put("L"), M is N - 40, toroman(M).
toroman(N) :- N < 90, put("L"), M is N …
Run Code Online (Sandbox Code Playgroud) 我往往最终写入的Prolog代码涉及(在整个程序或状态的重要信息)的一些算术计算,通过:首先获得存储在谓词的值,然后重新计算的值,最后使用存储所述值的装置retractall
和assert
因为在Prolog中,我们不能使用两次赋值给变量is
(因此几乎每个需要修改的变量都是全局的).我已经知道这在Prolog中不是一个好习惯.在这方面,我想问:
为什么在Prolog中这是一个不好的做法(虽然我自己不喜欢通过上面提到的步骤只是为了拥有一种灵活的(可修改的)变量)?
有哪些一般方法可以避免这种做法?小例子将不胜感激.
PS我刚开始学习Prolog.我确实有C语言的编程经验.
我想说的一个不好的例子(在win-prolog中)如下:
:- dynamic(value/1).
:- assert(value(0)).
adds :-
value(X),
NewX is X + 4,
retractall(value(_)),
assert(value(NewX)).
mults :-
value(Y),
NewY is Y * 2,
retractall(value(_)),
assert(value(NewY)).
start :-
retractall(value(_)),
assert(value(3)),
adds,
mults,
value(Q),
write(Q).
Run Code Online (Sandbox Code Playgroud)
然后我们可以查询如下:
?- start.
Run Code Online (Sandbox Code Playgroud)
在这里,它非常简单,但在实际程序和应用中,上面显示的全局变量方法变得不可避免.有时候,上面给出的列表就像assert(value(0))
... 一样长,并且有更多的断言谓词来定义更多的变量.这样做是为了使不同功能之间的值的通信成为可能,并在程序运行期间存储变量状态.
最后,我想再知道一件事:尽管您提出了各种解决方案以避免它,但上述做法何时变得不可避免?
我是prolog的新手,所以这对我来说是一个很大的挑战.我应该在Prolog中实现一个简单的C语言.
the ultimate goal is to be able to execute something like this:
?- run([begin,a,:=,10,while,a,>,5,begin,write,a,a,:=,a,-,1,end,end]).
and get:
10
9
8
7
6
yes
Run Code Online (Sandbox Code Playgroud)
但是,我陷入了第一步.这是我迄今取得的成就.超出本地堆栈!
statement(Vars,_Vars) --> assign(Vars,_Vars).
statement(Vars,Vars2) --> statement(Vars,Vars1), statement(Vars1,Vars2).
assign(Vars,_Vars) --> default_assign(Vars,_Vars).
assign(Vars,_Vars) --> simple_assign(Vars,_Vars).
% a //default value 0
default_assign(Vars,_Vars) -->
var_name(Var_Name),
{update_vars([Var_Name,0],Vars,_Vars)}.
% a = 0
simple_assign(Vars,_Vars) -->
var_name(Var_Name),[=],var_value(Var_Value),
{update_vars([Var_Name,Var_Value],Vars,_Vars)}.
% a = b
simple_assign(Vars,_Vars) -->
var_name(Var_Name1),[=],var_name(Var_Name2),
{
update_vars([Var_Name1,Var_Value],Vars,_Vars)
}.
var_name(Var_Name) --> [Var_Name],{\+number(Var_Name2)}.
var_value(Var_Value) -->[Var_Value],{number(Var_Value)}.
% found match, update
update_vars(Var,Vars,_Vars):-
member(Var,Vars),
update(Var,Vars,_Vars),
_Vars\==[].
% no match, …
Run Code Online (Sandbox Code Playgroud) 我想更好地了解DCG的使用.为了做到这一点,我尝试将LearnPrologNow书中的一些练习翻译成DCG表示法.但是,我失败了.
我试图编写一个程序,只列出列表中的最后一个元素.就这样.我只是想不出正确的DCG语法来做到这一点.我想我找出了应该是的"基本案例":
最后 - > [X | []].
其中X是最后一个元素.如何让Prolog以递归的方式进入列表?或者我是否以错误的方式思考DCG?
我想创建一个像这样的语言被接受的DCG:
正如您所看到的,这意味着a和b的特定顺序,然后是c,然后再次与c之前的顺序完全相同.如果不满足这些条件,它将失败.
我目前在这里采用我的方法(工作,但也识别错误的单词)
s --> x, s, x.
s --> [c].
x --> [a].
x --> [b].
Run Code Online (Sandbox Code Playgroud)
你们有人可以帮我解决我需要改变的问题吗?我不知道该怎么做.非常感谢.
我想在Prolog中学习更多关于Definite Clause Grammar的内容,我正在网上搜索一些书和教程.
我已经在"学习Prolog Now","Prolog的艺术"和Swi-Prolog的教程中看到了一些东西,但是没有一个能够讲述它们.
任何人都可以给我一些关于这个主题的详尽书籍吗?
谢谢 :)
我正在尝试将我的词法分析器和解析器分开,基于Prolog和自然语言分析这本书的模糊建议,这本书并没有详细介绍lexing/tokenizing.所以我给它一个镜头,看到几个小问题向我表明我有一些明显的缺失.
我所有的小标记解析器似乎都正常工作; 目前,这是我的代码片段:
:- use_module(library(dcg/basics)).
operator('(') --> "(". operator(')') --> ")".
operator('[') --> "[". operator(']') --> "]".
% ... etc.
keyword(array) --> "array".
keyword(break) --> "break".
% ... etc.
Run Code Online (Sandbox Code Playgroud)
它有点重复,但似乎有效.然后我有一些我不太喜欢的东西,欢迎提出建议,但似乎有效:
id(id(Id)) -->
[C],
{
char_type(C, alpha)
},
idRest(Rest),
{
atom_chars(Id, [C|Rest])
}.
idRest([C|Rest]) -->
[C],
{
char_type(C, alpha) ; char_type(C, digit) ; C = '_'
},
idRest(Rest).
idRest([]) --> [].
int(int(Int)) --> integer(Int).
string(str(String)) -->
"\"",
stringContent(Codes),
"\"",
{
string_chars(String, Codes)
}.
stringContent([C|Chars]) -->
stringChar(C), stringContent(Chars).
stringContent([]) --> …
Run Code Online (Sandbox Code Playgroud) 我已经把我的思绪包裹了很多,无法理解.是否可以使用回溯生成以这种格式生成列表的脚本:
[a]
[a,b]
[a,b,a]
[a,b,a,b]
...
Run Code Online (Sandbox Code Playgroud)
我已经制作了一个一次生成两个元素但我的头开始受伤试图制作一个产生"a",下一次"b"和下一个"a"等等.
这是一次两个元素的脚本:
ab([a]).
ab([b,a|T]):-ab([a|T]).
ab([a,b|T]):-ab([b|T]).
Run Code Online (Sandbox Code Playgroud) dcg ×10
prolog ×10
clpfd ×1
declarative ×1
grammar ×1
interpreter ×1
list ×1
numbers ×1
parsing ×1
scheme ×1