0

EG1 - с помощью let

(defun demo1() 
(let ((a 1) 
     (b 2)) 
    ; these print fine 
    (print a) 
    (print b))) 

(demo1) 
; these get "no value" errors, as expected 
(print a) 
(print b) 

выход на:Можете ли вы создавать локальные переменные без `let`?

1 
2 *** - EVAL: variable A has no value 

ЭГ2 - без let переменные избежать

(это очень удивительно для тех, кто используется для более современные правила, такие как, например, ruby's)

(defun demo2() 
(setf a 1) 
(setf b 2) 
; these print fine 
(print a) 
(print b)) 

(demo2) 
; these escape, and also print with no error! 
(print a) 
(print b) 

выход:

1 
2 
1 
2 

, как вы можете сделать их не бежать?
я monkey'd вокруг с setq и defvar
(которые были упомянуты в единственных результатов я мог бы найти путем поиска документации на «локальные переменные»)
, но нет радости на всех

EG3 - пытается использовать макрос

(
это практическая проблема, я хотел бы решить в первую очередь -
синтаксис let сил использовать дополнительные слои,
круглые скобки и обернуть всю функцию тело в наружном слое,
, который только делает его труднее читать и писать без причины
(так как в подавляющем большинстве случаев наиболее распространенный случай использования для let
всегда включает в себя всю функции тела и ничего),
, так что я хотел сделать with макрос вместо
)

(defmacro with (&rest list-of-pairs) 
(loop for (name value) in list-of-pairs 
    do `(setf ,name ,value) ;A 
    ; do (setf name value)  ;B 
    ; (i tried both A and B) 
)) 

(defun demo3() 
(with (a 1) 
     (b 2)) 
; this gets a "no value" error when called 
(print a) 
(print b)) 

(demo3) 
; it never even gets to this point cuz of the above error 
(print a) 
(print b) 

выход:

*** - PROGN: variable A has no value 

Как вы можете заставить переменные сбежать в область функций, а не дальше?

[
this question спрашивает

может кто-нибудь сказать мне, как определить локальную переменную в лепет, кроме пусть?

, но ни один из ответов не было полезно для меня
]

EDIT-TO-ADD ЭГ4

думать о том, что loop макрос работает
(с точки зрения кого-то , вызывающий, не понимая его внутренних компонентов, я имею в виду) ...
ну, посмотрите:

(loop for i from 1 to 5 
do (print i)) 

я еще не знаю, что такое определение loop выглядит,
но это абстрактно-то вроде этого, права ?:

(defmacro loop ([args somehow, 
       including the `sexpr` 
       which goes after the `do` keyword in the macro call]) 
[other stuff] 
do ([sexpr]) 
[other stuff]) 

(я сосредотачиваюсь на do ключевое слове в качестве примера только потому, что синтаксис вызова относительно прост.)

так, что я на самом деле нужно сделать, это сделать свой собственный my-defun макрос
и включают в себя with ключевое слово,
Право?

что-то вроде этого:

(defmacro my-defun ([args somehow, 
        including a `paired-list-of-names-and-values` 
        to go after a `with` keyword in the macro call]) 
(let 
    ([paired-list-of-names-and-values]) 
    ([function body]))) 

(my-defun demo4() 
with (
(a 1) 
(b 2) 
) 
; this should print 
(print a) 
(print b)) 

(demo4) 
; this should get a "no value" error 
(print a) 
(print b) 

я на правильном пути здесь?

если да, то откуда я могу перейти отсюда?

как, какие простые, прямые макроопределения я могу посмотреть, чтобы побудить их работать?
или что-то подобное

+2

«синтаксис' let' заставляет вас использовать дополнительные слои, круглых скобок и обернуть всю функцию тело в наружном слой, , который просто затрудняет чтение и запись без причины ». Вам не хватает важного момента: обертка их в круглых скобках не оставляет никаких сомнений в их объеме. Если ваши функции дойдут так долго, что «дополнительный слой парнеров» является проблемой, то вы делаете что-то не так;) –

+0

hmmm ... я считаю, что этот аргумент очень неубедительный в этом случае? я понял это и отправил его как ответ на мой собственный вопрос. я положил mindif, используя оба способа в конце, чтобы помочь глазному яблоку, насколько он стоит того, что было (вы можете скопировать их каждый в буфер и быстро перевернуть назад, чтобы действительно визуально выделить различия), и ... я все еще подумайте, что это имеет смысл, вы знаете? нет сомнений в объеме, потому что он просто завершает 'let' и подходит к концу вызова' my-defun'. –

ответ

0

[EDIT:
я просто понял, что я перепутался на обработке arguement,
так что мое «решение» сломано
, если не будет по крайней мере, три список дается my-defun после списка параметров ,

Я положил (я думаю) фактическое рабочее решение в конце.
]

Я действительно понял это!

это не слишком сложно,
даже для новыхb.

(
я имею в виду,
я не удивлюсь, если ужасные вещи будут происходить, если один на самом деле пытались использовать его в «реальном коде»,
потому реберных случаев или что-то,
, но это работая проверка концепции
)

во всяком случае, вот определение my-defun макро,
работает, как я описал в eg4 в моем вопросе:

(
пожалуйста, никто редактировать странное форматирование -
я понимаю, что это нестандартный,
, но это действительно помогает newbs прочитать сложный новый материал.
Я имею в виду,
, если другой новыйb, как я когда-либо читал это,
Я думаю, что это поможет им значительно.
)

(defmacro my-defun (name params withsymbol withlist &body body) 
(cond 
    ((equal withsymbol 'with)  
           ; (print 'withsymbol_set_to_) ;diagnostic 
           ; (print withsymbol)   ;diagnostic 
           ; (print 'withlist_set_to_)  ;diagnostic 
           ; (print withlist)    ;diagnostic 
           ; (print      ;diagnostic 
           `(defun ,name ,params   
            (let ,withlist    
            (progn ,@body)    
            )        
           )        
           ;)        ;diagnostic 
    )        
    (t       
           ; (print 'withsymbol_not_set_to_with_but_) ;diagnostic 
           ; (print withsymbol)      ;diagnostic 
           ; (print 'withlist_set_to_)     ;diagnostic 
           ; (print withlist)       ;diagnostic 
           ; (print         ;diagnostic 
           `(defun ,name ,params      
            (progn ,withsymbol ,withlist ,@body)  
           )           
           ;)           ;diagnostic 

    ) 
) 
) 

первый тест, с with:

(my-defun demo4 (x) 
with (
    (a 1) 
    (b 2) 
) 
; this prints! 
(print a) 
(print b) 
(print x) 
) 
(demo4 "hi") 
; this correctly gets a "no value" error! 
(print a) 
(print b) 
(print x) 

выход:

1 
2 
"hi" 

выход с диагностическими линиями раскомментирована:

WITHSYMBOL_SET_TO_ 
WITH 
WITHLIST_SET_TO_ 
((A 1) (B 2)) 
(DEFUN DEMO4 (X) (LET ((A 1) (B 2)) (PROGN (PRINT A) (PRINT B) (PRINT X)))) 
1 
2 
"hi" 

второе испытание, без with:

(так он действует точно так же, как обычный defun)

(my-defun demo4 (x) 
; (this stuff also prints) 
(print "i am not the withsymbol") 
(print "this is not the withlist") 
; this prints! 
(print "symbol 'a would have no value") 
(print "symbol 'b would have no value") 
(print x) 
) 

(demo4 "hi") 
; this correctly gets a "no value" error! 
'(print a) 
'(print b) 
'(print x) 

выход:

"i am not the withsymbol" 
"this is not the withlist" 
"symbol 'a would have no value" 
"symbol 'b would have no value" 
"hi" 

выход с диагностическими линиями раскомментирована:

WITHSYMBOL_NOT_SET_TO_WITH_BUT_ 
(PRINT "i am not the withsymbol") 
WITHLIST_SET_TO_ 
(PRINT "this is not the withlist") 
(DEFUN DEMO4 (X) 
(PROGN (PRINT "i am not the withsymbol") (PRINT "this is not the withlist") (PRINT "symbol 'a would have no value") 
    (PRINT "symbol 'b would have no value") (PRINT X))) 
"i am not the withsymbol" 
"this is not the withlist" 
"symbol 'a would have no value" 
"symbol 'b would have no value" 
"hi" 

минимально различные примеры:

использованием defun с let
и использованием my-defun с with
(просто хотел глазное яблоко, в какой степени результат выглядит стоит свеч XD)

( defun demo (x) 
(let (
     (a 1) 
     (b 2) 
    ) 
    (print a) 
    (print b) 
    (print x) 
) 
) 

(my-defun demo (x) 
with (
     (a 1) 
     (b 2) 
    ) 
(print a) 
(print b) 
(print x) 
) 

ФАКТИЧЕСКИ рабочего раствора (I НАДЕЖДА):

(defmacro fun (name params &rest rest) 
(let (
     (withsymbol (car rest)) 
     (withlist (car (cdr rest))) 
     (body  (cdr (cdr rest))) 
    ) 
    ; (p withsymbol ) ;;debug 
    ; (p withlist ) ;;debug 
    ; (p body  ) ;;debug 
    (cond 
    ((equal withsymbol 'with)  
           ; (print 'BRANCH_A)  ;;debug 
           ; (print    ;;debug 
           `(defun ,name ,params 
            (let* ,withlist  
            (progn ,@body)  
            )      
           )      
           ;)      ;;debug 
    )        
    (t       
           ; (print 'BRANCH_B)  ;;debug 
           ; (print    ;;debug 
           `(defun ,name ,params 
            (progn ,@rest)  
           )      
           ;)      ;;debug 

    ) 
) 
) 
) 
;; for debugging 
(defmacro p (symbol) 
`(format t "~A ~A~%" ',symbol ,symbol) 
) 

хотя t шляпа была самой ранней рабочей версией кода, , так что, возможно, я испортил ее, не заметив, переименовывая переменные не полностью или что-то в этом роде.

самого последний код, который я на самом деле просто тестированием является более сложным:

;; used in debug 
(defmacro p (symbol) 
`(format t "~A ~A~%" ',symbol ,symbol)) 

(defmacro mac-or-fun (which-one name params rest) 
(let (
     (withsymbol (car rest)) 
     (withlist (car (cdr rest))) 
     (body  (cdr (cdr rest))) 
    ) 
    ; (p withsymbol ) ;;debug 
    ; (p withlist ) ;;debug 
    ; (p body  ) ;;debug 
    (cond 
    ((equal withsymbol 'with)  
           ; (print 'BRANCH_A)   ;;debug 
           ; (print     ;;debug 
           `(,which-one ,name ,params 
            (let* ,withlist   
            (progn ,@body)   
            )       
           )       
           ;)       ;;debug 
    )        
    ((equal withsymbol 'omwith) 
           ; (print 'BRANCH_A)   ;;debug 
           ; (print     ;;debug 
           `(,which-one ,name ,params 
            (omlet ,withlist   
            (progn ,@body)   
            )       
           )       
           ;)       ;;debug 
    )        
    (t       
           ; (print 'BRANCH_B)   ;;debug 
           ; (print     ;;debug 
           `(,which-one ,name ,params 
            (progn ,@rest)   
           )       
           ;)       ;;debug 

    ) 
) 
) 
) 
(defmacro fun (name params &rest rest) 
    `(mac-or-fun defun ,name ,params ,rest)) 
(defmacro mac (name params &rest rest) 
    `(mac-or-fun defmacro ,name ,params ,rest)) 


;; for use in tests 
(defun ps (&rest stringlist) 
    (format t "~A~%" (eval `(concatenate 'string ,@stringlist)))) 
(defparameter *vs-use-count* 0) 
(defmacro vs (&rest title) 
(setf *vs-use-count* (+ 1 *vs-use-count*)) 
(ps " 

SECTION " (write-to-string *vs-use-count*) " " (write-to-string title) " -" 
) 
) 

;;;tests 
(progn 

(vs fun works with "with") 
(fun f() 
    with ((a 1)) 
    (print a) 
    ) 
(f) 
(vs fun works with "nil") 
(fun f() 
    () 
    ) 
(print(f)) 

(vs original fun test with "with") 
(fun demo4 (x) 
with (
    (a 1) 
    (b 2) 
) 
; this prints! 
(print a) 
(print b) 
(print x) 
) 
(demo4 "hi") 
; these would correctly gets a "no value" error! 
'(print a) 
'(print b) 
'(print x) 

(vs original fun test with no "with") 
(fun demo4 (x) 
; (this stuff also prints) 
(print "i am not the withsymbol") 
(print "this is not the withlist") 
; this prints! 
(print "symbol 'a would have no value") 
(print "symbol 'b would have no value") 
(print x) 
) 

(demo4 "hi") 
; these would correctly gets a "no value" error! 
'(print a) 
'(print b) 
'(print x) 




(vs mac works with "with") 
(mac m() 
    with ((a 1)) 
    (print a) 
    ) 
(m) 

(vs mac works with "nil") 
(mac m() 
    () 
    ) 
(print(m)) 
) 


;;; more stuff, 
;;; leading up to the macro `omlet`, 
;;; which is used in `mac-or-fun` 
(fun pair-up (l) 
with (
    (a  (car l)  ) 
    (b  (car (cdr l)) ) 
    (l-past-b (cdr (cdr l)) ) 
) 
(cond 
    (
    (equal 2 (length l)) 
    (list l) 
) 
    (t 
    (cons (list a b) (pair-up l-past-b)) 
) 
) 
) 

(fun crack-1 (eggs) 
    with (
     (paired-list (pair-up eggs)) 
     (paired-list (loop for (k v) in paired-list collect `(,k ',v))) 
    ) 
    paired-list 
) 
(fun crack-2 (eggs) 
    with (
     (key-name   (car eggs)) 
     (value-name   (car (cdr eggs))) 
     (eggs    (cdr (cdr eggs))) 
     (paired-list  (pair-up eggs)) 
     (keys-list   (loop for pair in paired-list collect (first pair))) 
     (values-list  (loop for pair in paired-list collect (second pair))) 
     (key-name-keys  (list key-name keys-list)) 
     (value-name-values (list value-name values-list)) 
     (paired-list  (append paired-list (list key-name-keys value-name-values))) 
     (paired-list  (loop for (k v) in paired-list collect `(,k ',v))) 
    ) 
    paired-list 
) 
(fun crack (eggs) 
    (if 
     (and 
      (equal '- (car eggs)) 
      (oddp (length eggs)) 
     ) 
     (crack-2 (cdr eggs)) 
     (crack-1 eggs) 
    ) 
) 
(mac omlet (eggs &body body) 
    with ((to-let (crack eggs))) 
    `(let ,to-let (progn ,@body)) 
) 
(mac lemego (&rest eggs) 
    with ((to-set (crack eggs))) 
    (loop for (name value) in to-set 
     do (eval `(setf ,name ,value)) 
    ) 
) 


;;; more tests 
(progn 

(vs omlet 1) 
(omlet (
    x a 
    y b 
    z c 
) 
    (print x ) 
    (print y ) 
    (print z ) 
) 

(vs omlet 2) 
(omlet (
    - names digits 
    one  1 
    two  2 
    three 3 
) 
    (print one ) 
    (print two ) 
    (print three ) 
    (print names ) 
    (print digits ) 
) 


(vs fun with omwith 1) 
(fun f() 
omwith (
    x a 
    y b 
    z c 
) 
    (print x ) 
    (print y ) 
    (print z ) 
) 
(f) 

(vs fun with omwith 2) 
(fun f() 
omwith (
    - names digits 
    one  1 
    two  2 
    three 3 
) 
    (print one ) 
    (print two ) 
    (print three ) 
    (print names ) 
    (print digits ) 
) 
(f) 


(vs lemego 1) 
(lemego 
x a 
y b 
z c 
) 
(print x ) 
(print y ) 
(print z ) 


(vs lemego 2) 
(lemego 
- names digits 
one  1 
two  2 
three 3 
) 
(print one ) 
(print two ) 
(print three ) 
(print names ) 
(print digits ) 
) 
9

Простое правило: SETF или SETQ не создают переменные. Ни местные, ни глобальные. Они просто задают переменные.

Никогда не устанавливайте неопределенную переменную, используя SETQ и SETF. Это Common Lisp, а не Ruby.

Он также не помогает создавать формы SETF с макросом. Почему это должно иметь значение?

Определение локальных переменных

Если вы смотрите в Common Lisp стандарта, есть зиллионы конструкции, которые позволяют определить локальные переменные: DEFUN, DEFMETHOD, LET, LET*, DO, DOTIMES, FLET, LABELS, LAMBDA, DESTRUCTURING-BIND, MULTIPLE-VALUE-BIND, ...

Локальные переменные в функциях

Если посмотреть на функции, список аргументов для функций позволяет определить локальные переменные:

  • обязательный аргумент
  • опциональный аргумент
  • ключевое слово аргумент
  • Вспомогательный аргумент
  • аргумент остальные

Вы можете определить функции с LAMBDA, DEFUN ...

Пример для &optional:

((lambda (a &optional (b 20)) 
    ... ; a and b are known here inside the function 
) 
10) ; we don't need to pass an arg for `b`, optional! 

Пример &aux:

((lambda (a &aux (b (+ a 20))) 
    ... ; a and b are known here inside the function 
) 
10) ; we CAN't pass an arg for `b`, auxiliary! 

Переменные LOOP

Вам не нужно угадать, что делает LOOP макрос, вы можете попросить Лисп, чтобы показать вам - здесь с помощью LispWorks:

CL-USER 27 > (pprint (macroexpand '(loop for i from 1 to 5 
             do (print i)))) 

(BLOCK NIL 
    (MACROLET ((LOOP-FINISH() '(GO #:|end-loop-82961|))) 
    (LET ((I 1) 
      (#:|to-82964| 5) 
      (#:|by-82965| 1)) 
     (TAGBODY (PROGN (SYSTEM::INTERNAL-IF (OR (> I #:|to-82964|)) 
         (GO #:|end-loop-82961|))) 
     #:|begin-loop-82960| 
     NIL 
     (PRINT I) 
     (PROGN 
     (LET ((#:|temp-82966| (+ I #:|by-82965|))) 
      (SETQ I #:|temp-82966|)) 
     (SYSTEM::INTERNAL-IF (OR (> I #:|to-82964|)) 
      (GO #:|end-loop-82961|))) 
     (GO #:|begin-loop-82960|) 
     #:|end-loop-82961| 
     (RETURN-FROM NIL NIL))))) 

Как вы можете видеть, что расширяется в форму, где переменной i вводится LET. Он также расширяется до формы, которая использует конструкцию goto.

Как вы можете видеть, вы можете реализовать очень причудливый синтаксис - как синтаксис LOOP - в Lisp. Но реализация LOOP велика и нетривиальна. Ничего для новичка.

+0

поэтому, в моем eg3, я хочу сохранить определение 'demo3' и все равно и изменить только определение макроса' with', чтобы он работал (т. Е. Получает тот же результат, что и eg1). я не могу понять из вашего ответа - вы говорите, что ** я должен иметь возможность использовать информацию, которую вы мне дали? ** или вы говорите, что ** это просто невозможно? **> :? (я очень * новичок в lisp, просто сделал [elmart] (http: //art2.ph-freiburg.de/Lisp-Course) и [lisptutorjr] (http://alarm.cti.depaul.edu/lisptutor/login), а затем получил информацию о том, как писать макросы у друга, который знает чуть больше, чем я. .) –

+0

@Owen_R: используйте LET или список функций лямбда. Не боритесь с языком. –

+0

так просто подтвердить, это определенно «это просто невозможно»? –

1

Мне нравится, как привязки вводятся в Lisp, и я скучаю по нему на других языках. Однако я не пытаюсь изменить их по своему вкусу. Вместо этого я следую конкретным идиомам других языков. В комментарии, вы спросите:

ты говоришь, что я должен быть в состоянии использовать информацию вы игру мне сделать это, или вы говорите, что это просто не возможно?

На самом деле, Rainer Joswig говорит вам, что вы не должны сделать это, по той же причине, что вы не вводить BEGIN и END макросов в коде C заменить фигурные скобки: просто работать с существующим языком вместо непосредственно пытается «исправить» его.

Кстати, пожалуйста, поймите, что существующая конструкция LET: не авария, и работа в соответствии с ожиданиями. Тот факт, что выглядит странно для вас «с современной точки зрения» (см. OCaml/F #), не означает, что он неправильный или плохо разработан.Я не знаю, что вы имеете в виду со следующим комментарием:

может правильно тени и unshadow определения переменной для параметров, передаваемых в функцию

... но я могу вам сказать, что это не имеет большого смысла как есть. Проконсультируйтесь с Online Tutorials for programming Common Lisp, чтобы лучше просмотреть Lisp, прежде чем пытаться его модифицировать.

+1

Пример неправильный. :-) Переменные конструкторы определений в LOOP должны быть все до тела LOOP. Вы не можете смешивать объявления тела и переменных. Итак, больше нет СО после первого DO. Проверьте синтаксис LOOP. Последовательность предложений для LOOP: name * variable * main *. –

+1

@RainerJoswig Ах дерьмо, я протестировал его, он работал и не удосужился проверить правила. Спасибо, я отредактирую – coredump

+1

Некоторые реализации жалуются на синтаксическую ошибку. ;-) –

Смежные вопросы