我正在尝试学习Common Lisp,我想知道如何使用类似于Prolog的解析器作为单项式,并且不知道从哪里开始。
as_monomial(X, m(X, 0, [])) :- number(X), !.
as_monomial(^(Y, Z), m(1, Z, [v(Z, Y)])) :- !.
as_monomial(^(X, 0), m(1, 0, [])) :- !.
as_monomial(*(X, ^(Y, Z)), m(G, K, Q)) :-
as_monomial(X, m(G, TD, Vars)),
K is (TD + Z),
ordinamonomio([v(Z, Y)| Vars], Q),
!.
as_monomial(*(X, Y), m(G, K, Q)) :-
as_monomial(X, m(G, TD, Vars)),
K is (TD + 1),
ordinamonomio([v(1, Y)| Vars], Q),
!.
as_monomial(-(X), m(Q, Y, L)) :-
as_monomial(X, m(A, Y, L)),
Q is A *(-1),
!.
as_monomial(X, m(1, 1, [v(1, X)])).
答案 0 :(得分:3)
在Prolog代码中,您主要依赖于模式匹配和递归,但不是回溯,因此您可以轻松地将其转换为Common Lisp而无需进行重大修改。我可以根据generic functions向您展示一个骨架。如果您不熟悉Common Lisp,我强烈建议您阅读Practical Common Lisp书。
DEFGENERIC
声明一个泛型函数,即根据一个或多个参数的类型或值动态调度的函数。
(defgeneric as-monomial (term)
(:documentation "Express a term as a monomial."))
DEFMETHOD
根据其参数的类型或值来专门化泛型函数。例如,您可以具有数字的特定实现:
(defmethod as-monomial ((term number))
`(m ,term 0 ()))
...和另一个cons
单元格,即复合词:
(defmethod as-monomial ((term cons))
(destructuring-bind (operator left &optional right) term
(case operator
(^ ...)
(* ...)
(- ...))
见DESTRUCTURING-BIND
。
您还可以使用默认行为:
;; fallback case
(defmethod as-monomial (term)
`(m 1 1 ((v 1 ,term))))
当然,您可以定义仅使用case
或destructure-bind
的单个函数,但通用方法可以更好地扩展。对于复杂的模式匹配需求(这里不是这种情况,IMO),您可以使用模式匹配库,如trivia。
答案 1 :(得分:1)
参考:Lisprolog - Interpreter for a simple Lisp, written in Prolog
这使用Prolog DCG,我发现Ivan Bratko的书籍“Prolog Programming for Artificial Intelligence”可以更好地学习DCG。
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Lisprolog -- Interpreter for a simple Lisp. Written in Prolog.
Written Nov. 26th, 2006 by Markus Triska (triska@metalevel.at).
Public domain code.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- set_prolog_flag(double_quotes, chars).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Parsing
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
parsing(String, Exprs) :- phrase(expressions(Exprs), String).
expressions([E|Es]) -->
ws, expression(E), ws,
!, % single solution: longest input match
expressions(Es).
expressions([]) --> [].
ws --> [W], { char_type(W, space) }, ws.
ws --> [].
% A number N is represented as n(N), a symbol S as s(S).
expression(s(A)) --> symbol(Cs), { atom_chars(A, Cs) }.
expression(n(N)) --> number(Cs), { number_chars(N, Cs) }.
expression(List) --> "(", expressions(List), ")".
expression([s(quote),Q]) --> "'", expression(Q).
number([D|Ds]) --> digit(D), number(Ds).
number([D]) --> digit(D).
digit(D) --> [D], { char_type(D, digit) }.
symbol([A|As]) -->
[A],
{ memberchk(A, "+/-*><=") ; char_type(A, alpha) },
symbolr(As).
symbolr([A|As]) -->
[A],
{ memberchk(A, "+/-*><=") ; char_type(A, alnum) },
symbolr(As).
symbolr([]) --> [].
引用是Markus Triska's website的一部分,其中包含许多其他有用的Prolog资源。他也积极参与GitHub