我在Lisp中與defpackage
擦肩而過,並開始了一個可恥的開始,即一個我無法理解的錯誤。爲什麼只有兩個元素在我的代碼封裝後才被識別?
下面的代碼是試圖創建一個子語言來執行向量中的中綴操作。我想將它用於涉及一些線性代數的項目。
我的代碼的'肉'是parse-infix
。該函數找到具有最高優先級的運算符,調用apply-op
以用operator (operand, operand)
替換所述運算符及其操作數,從而縮小列表並迭代,直到列表僅包含結果。支持的運算符有四條規則,相等(將結果綁定到Lisp符號)和向量級聯。
下面的代碼,疣和所有:
(defpackage :infix
(:use :common-lisp)
(:export operator-list
operators
parse-infix
infix))
(in-package :infix)
(defun parse-input (a)
"Turns symbols into numbers as necessary while reading an expression"
(if (symbolp a) (symbol-value a) a))
;; Definition of structure containing data for one operator
(defmacro mapf (op type)
""
`(lambda (a b)
(map ,type #'(lambda (x y)
(funcall ,op x y)) (parse-input a) (parse-input b))))
(defstruct (operator
(:conc-name op-)
(:constructor op (sym &key (func (mapf sym 'vector)) priority associativity n-operands)))
sym ; Operator symbol
func ; Function to be applied to operands
priority ; Other operators attributes
(associativity 'left-to-right) ; Evaluation order for operators
; that appear more than once in a row
(n-operands 2)) ; Number of operands (NOT IMPLEMENTED)
(defmacro operator-list (&body ops)
"Produces an operator list from a list of operator structs."
`(mapcar #'(lambda (y) (apply #'op
(mapcar #'(lambda (x) (if (listp x) (eval x) x)) y))) ',ops))
(defparameter operators
(operator-list
(+ :priority 4)
(- :priority 4)
(* :priority 3)
(/ :priority 3)
(^ :priority 2 :func expt :associativity right-to-left)
(& :priority 2 :func (lambda (x y) (concatenate 'vector x y)))
(= :priority 10 :func (lambda (x y) (set (intern (string x)) y))))
"Default set of operators, which perform arithmetic operations on
vectors lengthwise. If one vector is shorter than the other, the result
is truncated.")
(defun apply-op (b)
"Reads a segment of a list of the format operand/operator/operand (in 3 consecutive
cells) and leaves operator (operand, operand) in a single cell."
(setf (car b) (funcall (op-func (caadr b))
(car b)
(caddr b))
(cdr b) (cdddr b)))
(defun parse-infix (b &key (operator-list operators))
"Parses an infix expression by calling apply-op repeatedly until the entire
expression is processed."
(let ((expr (mapcar #'(lambda (x)
(case (type-of x)
(symbol (or (member x operator-list :key #'op-sym) x))
(cons (parse-infix x))
(otherwise x))) b)))
(loop while (cdr expr) do
(apply-op (reduce #'(lambda (x y &aux (op1 (caadr x)) (op2 (caadr y)))
(if (or (< (op-priority op2) (op-priority op1))
(and (= (op-priority op1) (op-priority op2))
(eq (op-associativity op1) 'right-to-left))) y x))
(remove-if #'listp (mapcon #'list expr) :key #'caddr)))
finally (return (car expr)))))
(defmacro infix (&rest b)
"Wrapper to create lists for parse-infix"
`(parse-infix ',b))
而這裏的障礙。該功能似乎是工作...
? (infix (#(2 3) + #(4 5)) * #(2 2))
#(12 16)
? (infix (#(100) & (#(2 3) + #(4 5)) * #(2 2))) ; '& is concatenation
#(200 12)
? (infix A = #(5 5) + #(10 10))
#(15 15)
? A
#(15 15)
...但是當我離開包,級聯(&)運算符突然「死亡」:
? (in-package :cl-user)
#<Package "COMMON-LISP-USER">
? (infix:infix A = #(5 5) + #(10 10))
#(15 15)
? (infix:infix (#(2 3) + #(4 5)) * #(2 2))
#(12 16)
? (infix:infix (#(100) & (#(2 3) + #(4 5)) * #(2 2)))
> Error: The value & is not of the expected type LIST.
> While executing: (:INTERNAL INFIX:PARSE-INFIX), in process listener(1).
> Type :POP to abort, :R for a list of available restarts.
> Type :? for other options.
1 >
我試圖跟蹤包的並注意到,無論出於何種原因,'&在我離開infix
包時不再被認定爲操作員。我不知道爲什麼會出現這種情況。任何輸入讚賞。
PS。很多人可能注意到,所有這些都在Clozure Common Lisp中。
它也許值得檢查符號的名稱,而不是實際的符號標識。這就是**循環**所做的。例如,你可以做'(循環:用於列表中的x)'或'(循環#:用於列表中的x)「等。 –
賓果!現在正在工作。雖然採取了稍微不同的方法。我將符號轉換爲字符串以利用'(string'infix:&)==(string'&)' –
您也可以使用字符。 – sds