เอาชนะโอเปอเรเตอร์พิเศษโดยใช้ MACROLET หรือไม่

ฉันกำลังพยายามแทนที่ IF ในเครื่อง (จุดประสงค์คือการฝัง DSL)

พฤติกรรมทำให้ฉันสับสนจริงๆ ใน SBCL:

(macrolet ((if (x) x)) 
  (if 'x)) ; => X

(macrolet ((if (x) x)) 
  (let ((x 2)) 
    (if 'x))) ; => Execution of a form compiled with errors.

(let ((x 2)) 
  (macrolet ((if (x) x)) 
    (if 'x))) ; => Execution of a form compiled with errors.

มีความคิดบ้างไหมว่าทำไมมันถึงมีพฤติกรรมแบบนั้น?

ฉันยังลองใช้สัญลักษณ์ฝึกงาน xxx::if แต่ก็ไม่มีโชค SBCL ยังคงคิดว่ามันเป็นตัวดำเนินการพิเศษไม่ว่าจะอยู่ในแพ็คเกจใดก็ตาม

มีการแทนที่โอเปอเรเตอร์พิเศษในเครื่องอย่างถูกต้องหรือไม่? หรืออย่างน้อยก็แทนที่ตัวอักษร ซึ่งหมายความว่าเราสามารถพิมพ์ if และขยายได้ (การใช้เวทย์มนตร์ของผู้อ่านอาจช่วยได้ แต่ฉันไม่คุ้นเคย)

อัปเดต (แก้ไขแล้ว): ข้อความแสดงข้อผิดพลาดที่แน่นอนในวันที่ 2 ที่ฉันได้รับ

Execution of a form compiled with errors.
Form:
  (MACROLET ((IF (X)
             X))
  (IF 'X))
Compile-time error:
  Lock on package COMMON-LISP violated when binding IF as a local macro while in
package COMMON-LISP-USER.
See also:
  The SBCL Manual, Node "Package Locks"
  The ANSI Standard, Section 11.1.2.1.2
   [Condition of type SB-INT:COMPILED-PROGRAM-ERROR]

อันที่ 3 ก็คล้ายๆ กัน

ปรากฎว่าการใช้ xxx::if ทำให้ใช้งานได้ ฉันเพียงแต่ไม่ได้แชโดว์สัญลักษณ์อย่างถูกต้องในการทดลองครั้งก่อน

วิธีง่ายๆ ในการทำงาน:

(defpackage p)
(macrolet ((p::if (x) x)) 
  (let ((x 2)) 
    (p::if 'x))) ; => X

หากคุณต้องการสืบทอดตัวดำเนินการ CL ตามปกติอื่นๆ ใน P ให้ทำ (defpackage p (:use :cl) (:shadow if))


person BlueFlo0d    schedule 29.02.2020    source แหล่งที่มา
comment
ฉันได้รับข้อผิดพลาดจากอันแรก การล็อคบนแพ็คเกจ COMMON-LISP ถูกละเมิดเมื่อรวม IF เป็นแมโครในเครื่อง   -  person Barmar    schedule 29.02.2020
comment
ถ้าฉันใช้ p::if ฉันไม่ได้รับข้อผิดพลาดจากเวอร์ชัน 2 และ 3 เพียงคำเตือนเกี่ยวกับตัวแปร X ที่ไม่ได้ใช้ ซึ่งเข้าใจได้เนื่องจากคุณกำลังอ้างอิง x ในส่วนเนื้อความ ไม่ได้ใช้ตัวแปร   -  person Barmar    schedule 29.02.2020
comment
ทั้งคู่ส่งคืน 2 โดยไม่มีคำเตือนหากฉันลบเครื่องหมายคำพูดก่อน x   -  person Barmar    schedule 29.02.2020
comment
โอเค น่าสนใจ ก่อนหน้านี้ฉันทำ sb-ext:unlock-package :cl อาจรบกวนการล็อคแพ็คเกจใช่ไหม ให้ฉันลองใช้ REPL ใหม่   -  person BlueFlo0d    schedule 29.02.2020
comment
ฉันยังคงได้รับข้อผิดพลาดเดิมเมื่อฉันเรียกใช้ (let ((x 2)) (macrolet ((cl-user::if (x) x)) (cl-user::if 'x))) ในการทำซ้ำครั้งใหม่ ฉันใช้ SBCL 1.5.1 การใช้งานนี้ขึ้นอยู่กับหรือไม่?   -  person BlueFlo0d    schedule 29.02.2020
comment
อย่าใช้ cl-user::if สร้างแพ็คเกจของคุณเองและใช้ mypackage::if   -  person Barmar    schedule 29.02.2020
comment
ตกลง (defpackage p (:use :cl) (:shadow if)) (macrolet ((p::if (x) x)) (p::if 'x)) ใช้งานได้สำหรับฉันตอนนี้ ขอบคุณมาก!   -  person BlueFlo0d    schedule 29.02.2020
comment
ฉันเพิ่งทำ (make-package 'p) จากนั้นฉันก็ใช้ p::if ไม่จำเป็นต้องสืบทอดหรือทำเงาอะไร   -  person Barmar    schedule 29.02.2020
comment
โปรดแก้ไขคำถามและแสดงข้อความแสดงข้อผิดพลาดที่คุณได้รับ   -  person Barmar    schedule 29.02.2020
comment
แน่นอนว่าฉันต้องการใช้เนื้อหาอื่นๆ ของ CL ที่ให้มาใน DSL ด้วย (นั่นคือสาเหตุที่ฉันต้องการฝังมัน) ตกลง ฉันกำลังอัปเดตคำถามตอนนี้   -  person BlueFlo0d    schedule 29.02.2020
comment
โปรดสังเกตว่า (defpackage p) และ (make-package 'p) นั้นไม่ได้ระบุไว้สำหรับ Common Lisp แบบพกพา ไม่ได้กำหนดว่าแพ็คเกจใด ใช้ SBCL ใช้ ฉาวโฉ่ไม่มีเลย   -  person Rainer Joswig    schedule 29.02.2020


คำตอบ (1)


การเชื่อมโยงสัญลักษณ์ if (สัญลักษณ์ที่อยู่ในแพ็คเกจ Common Lisp common-lisp:if) ถือเป็น พฤติกรรมที่ไม่ได้กำหนด .

หากคุณต้องการสร้างภาษามาโครซึ่งใช้ชื่อสัญลักษณ์เดียวกันกับ Common Lisp มาตรฐาน วิธีที่ดีที่สุดคือใช้แพ็คเกจอื่น เพื่อให้สิ่งที่ดูเหมือน if กลายเป็น mypackage:if จริงๆ

รายละเอียดเพิ่มเติม: ส่วนที่ 11.1.2.1.2 ระบุว่าการเชื่อมโยงสัญลักษณ์ของแพ็คเกจ Common Lisp ทั้งหมดนั้นเป็นพฤติกรรมที่ไม่ได้กำหนดไว้ ยกเว้นในกรณีที่ได้รับอนุญาตอย่างชัดเจน

การผูกสัญลักษณ์ Common Lisp ด้วย macrolet ได้รับอนุญาตอย่างชัดเจนในอนุประโยค 11.1.2.1.2.1:

"หากสัญลักษณ์ภายนอกของแพ็คเกจ COMMON-LISP ไม่ได้ถูกกำหนดให้เป็นฟังก์ชันมาตรฐาน มาโคร หรือตัวดำเนินการพิเศษ จะอนุญาตให้ผูกคำศัพท์เป็นมาโครได้ (เช่น ด้วยมาโครเล็ต)

ตัวอย่างเช่น เนื่องจากค่าคงที่ pi (เช่น cl:pi) ไม่ใช่ฟังก์ชัน มาโคร หรือตัวดำเนินการพิเศษ (macrolet ((pi ...)) ...) จึงสามารถประเมินได้โดยโปรแกรมที่สอดคล้อง

person Kaz    schedule 02.03.2020