อะไรคือความแตกต่างระหว่าง "set", "setq" และ "setf" ใน Common LISP?
อะไรคือความแตกต่างระหว่าง "set", "setq" และ "setf" ใน Common LISP?
คำตอบ:
แต่เดิมใน Lisp ไม่มีตัวแปรคำศัพท์ - เฉพาะตัวแปรแบบไดนามิก และไม่มี SETQ หรือ SETF เพียงฟังก์ชั่น SET
สิ่งที่เขียนตอนนี้:
(setf (symbol-value '*foo*) 42)
ถูกเขียนเป็น:
(set (quote *foo*) 42)
ซึ่งท้ายที่สุดก็คือย่อมาจาก SETQ (SET Quote):
(setq *foo* 42)
จากนั้นตัวแปรคำศัพท์เกิดขึ้นและ SETQ ก็ถูกนำมาใช้สำหรับการมอบหมายให้พวกเขาด้วยเช่นกันดังนั้นจึงไม่ใช่เรื่องง่ายที่จะล้อมรอบตลาดหลักทรัพย์
ต่อมามีบางคนคิดค้น SETF (เขตข้อมูล SET) เป็นวิธีทั่วไปในการกำหนดค่าให้กับโครงสร้างข้อมูลเพื่อทำมิเรอร์ค่า l ของภาษาอื่น:
x.car := 42;
จะเขียนเป็น
(setf (car x) 42)
สำหรับความสมมาตรและความเป็นเหตุเป็นผล SETF ได้จัดเตรียมฟังก์ชันการทำงานของ SETQ ณ จุดนี้มันจะถูกต้องที่จะบอกว่า SETQ เป็นแบบดั้งเดิมระดับต่ำและ SETF เป็นการดำเนินงานระดับสูง
จากนั้นสัญลักษณ์มาโครจะเกิดขึ้น ดังนั้นมาโครสัญลักษณ์นั้นสามารถทำงานได้อย่างโปร่งใสมันก็ตระหนักว่า SETQ จะต้องทำหน้าที่เหมือน SETF ถ้า "ตัวแปร" ที่กำหนดให้เป็นแมโครสัญลักษณ์จริงๆ:
(defvar *hidden* (cons 42 42))
(define-symbol-macro foo (car *hidden*))
foo => 42
(setq foo 13)
foo => 13
*hidden* => (13 . 42)
ดังนั้นเรามาถึงในปัจจุบัน: SET และ SETQ ยังคงเป็นภาษาที่เสื่อมโทรมของภาษาถิ่นที่เก่ากว่าและอาจจะถูกบูตจากผู้สืบทอดในที่สุดของ Common Lisp
f
จริง ๆ แล้วหมายถึงฟังก์ชั่นไม่ใช่เขตข้อมูล (หรือแบบฟอร์มสำหรับเรื่องนั้น) และให้การอ้างอิงดังนั้นในขณะที่ setf สำหรับเขตข้อมูลทำให้รู้สึกบางอย่างดูเหมือนว่ามันอาจไม่ถูกต้อง
set
เป็นฟังก์ชั่น ดังนั้นจึงไม่รู้จักสภาพแวดล้อม set
ไม่สามารถดูตัวแปรศัพท์ มันสามารถตั้งค่าสัญลักษณ์ - ค่าของการโต้แย้งเท่านั้น setq
ไม่ใช่ "set quote" อีกต่อไป ความจริงที่ว่าsetq
เป็นรูปแบบพิเศษไม่ใช่มาโครแสดงให้เห็นว่า
(set ls '(1 2 3 4)) => Error - ls has no value
(set 'ls '(1 2 3 4)) => OK
(setq ls '(1 2 3 4)) => OK - make ls to (quote ls) and then have the usual set
(setf ls '(1 2 3 4)) => OK - same as setq so far BUT
(setf (car ls) 10) => Makes ls '(10 2 3 4) - not duplicated by setq/set
(setq ls '(((1))))
, (setf (car (car (car ls))) 5)
เป็นพฤติกรรมที่ไม่ได้กำหนดเพราะค่าของls
เป็นค่าคงที่ (เช่นการปรับเปลี่ยนตัวอักษรสตริงใน C) หลังจาก(setq ls (list (list (list 1))))
, (setf (car (car (car ls))) 5)
ทำงานเช่นเดียวกับls->val->val->val = 5
ใน C.
setq
เป็นเช่นเดียวset
กับหาเรื่องแรกที่ยกมา - เป็นเหมือน(set 'foo '(bar baz))
ในทางกลับกันมันบอบบางจริงๆ - มันเหมือนกับ "อ้อม" ฉันแนะนำhttp://www.nano.com/lisp/cmucl-tutorials/LISP-tutorial-16.htmlเป็นวิธีที่ดีกว่าในการเริ่มต้นทำความเข้าใจมากกว่าคำตอบใด ๆ ที่นี่สามารถให้ ... ในระยะสั้นแม้ว่าจะใช้เวลา อาร์กิวเมนต์แรกเป็น "อ้างอิง" เพื่อที่จะทำงาน (เป็น ARG แรก) เพื่อตั้งค่ารายการภายในอาร์เรย์(setq foo '(bar baz))
setf
setf
(aref myarray 3)
setf
คุณสามารถใช้setf
แทนset
หรือsetq
ไม่ใช้ในทางกลับกันได้เนื่องจากsetf
ยังสามารถกำหนดค่าขององค์ประกอบแต่ละส่วนของตัวแปรได้หากตัวแปรนั้นมีองค์ประกอบของแต่ละบุคคล ดู exaples ด้านล่าง:
ตัวอย่างทั้งสี่จะกำหนดรายการ (1, 2, 3) ให้กับตัวแปรชื่อ foo
(set (quote foo) (list 1 2 3)) ;foo => (1 2 3)
(1 2 3)
(set 'foo '(1 2 3)) ;foo => (1 2 3) same function, simpler expression
(1 2 3)
(setq foo '(1 2 3)) ;foo => (1 2 3) similar function, different syntax
(1 2 3)
(setf foo '(1 2 3)) ;foo => (1 2 3) more capable function
(1 2 3)
setf
มีความสามารถเพิ่มของการตั้งค่าสมาชิกของรายการในfoo
ค่าใหม่
foo ;foo => (1 2 3) as defined above
(1 2 3)
(car foo) ;the first item in foo is 1
1
(setf (car foo) 4) ;set or setq will fail since (car foo) is not a symbol
4
foo ;the fist item in foo was set to 4 by setf
(4 2 3)
อย่างไรก็ตามคุณสามารถกำหนดมาโครสัญลักษณ์ที่แสดงรายการเดียวภายใน foo
(define-symbol-macro foo-car (car foo)) ; assumes FOO => (1 2 3)
FOO-CAR
foo-car ;foo-car is now a symbol for the 1st item in foo
1
(setq foo-car 4) ;set or setq can set the symbol foo-car
4
foo ;Lisp macros are so cool
(4 2 3)
คุณสามารถใช้defvar
ถ้าคุณยังไม่ได้กำหนดตัวแปรและไม่ต้องการให้มันมีค่าจนกระทั่งในภายหลังในรหัสของคุณ
(defvar foo2)
(define-symbol-macro foo-car (car foo2))
หนึ่งสามารถคิดSET
และSETQ
การสร้างระดับต่ำ
SET
สามารถกำหนดค่าของสัญลักษณ์
SETQ
สามารถกำหนดค่าของตัวแปร
แล้วก็ SETF
เป็นแมโครซึ่งมีการตั้งค่าหลายอย่าง: สัญลักษณ์ตัวแปรองค์ประกอบอาเรย์สล็อตอินสแตนซ์ ...
สำหรับสัญลักษณ์และตัวแปรหนึ่งสามารถคิดเป็นถ้าSETF
ขยายเข้าไปในและSET
SETQ
* (macroexpand '(setf (symbol-value 'a) 10))
(SET 'A 10)
* (macroexpand '(setf a 10))
(SETQ A 10)
ดังนั้นSET
และSETQ
จะใช้ในการใช้งานฟังก์ชั่นบางอย่างของSETF
ซึ่งเป็นโครงสร้างทั่วไปมากขึ้น คำตอบอื่น ๆ บางคำบอกเล่าเรื่องราวที่ซับซ้อนมากขึ้นเล็กน้อยเมื่อเราคำนึงถึงมาโครสัญลักษณ์
ฉันต้องการเพิ่มคำตอบก่อนหน้านี้ว่า setf เป็นมาโครที่เรียกใช้ฟังก์ชันเฉพาะขึ้นอยู่กับสิ่งที่ถูกส่งผ่านเป็นอาร์กิวเมนต์แรก เปรียบเทียบผลลัพธ์ของการขยายแมโครของ setf กับอาร์กิวเมนต์ชนิดต่าง ๆ :
(macroexpand '(setf a 1))
(macroexpand '(setf (car (list 3 2 1)) 1))
(macroexpand '(setf (aref #(3 2 1) 0) 1))
สำหรับอาร์กิวเมนต์บางประเภท "setf function" จะถูกเรียก:
(defstruct strct field)
(macroexpand '(setf (strct-field (make-strct)) 1))