[Этюд]Макрос "or"
От: Mr.Cat  
Дата: 16.04.09 14:08
Оценка: 5 (1)
Этюд актуален для любого языка с аппликативным порядком вычисления и макросами, однако в силу происхождения этюда — я предлагаю его в контексте scheme.

В scheme "or" — short-circuit операция, которая принимает произвольное число аргументов. Реализовать "or" можно в виде макроса.
Вот вариант реализация "or":
(define-syntax or
  (syntax-rules ()
    ((_) #f)
    ((_ e1 e2 ...)
     (let ((t e1))
       (if t t (or e2 ...))))))

Этот вариант "or" будем считать "неправильным", т.к. он обладает определенным недостатком (с приходом r6rs можно сказать, что двумя).

Вот такой вариант "or" (в нем появляется дополнительное условие) будем считать "правильным":
(define-syntax or
  (syntax-rules ()
    ((_) #f)
    ((_ e) e)
    ((_ e1 e2 e3 ...)
     (let ((t e1))
       (if t t (or e2 e3 ...))))))

В связи с этим, предлагаю ответить на два вопроса.

— Каким недостатком обладает "неправильный" по сравнению с правильным?
— Приведите пример кода, который будет по разному вести себя для "неправильной" и "правильной" реализации "or".

PS: Все-же этюд касается не только scheme, так что, если надо, могу немного рассказать о семантике вышеозначенных макросов или попытаться накидать аналогичные макросы, скажем, на nemerle.
Re: [Этюд]Макрос "or"
От: jartur Россия http://jartur.l-square.net;
Дата: 26.04.09 06:47
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>PS: Все-же этюд касается не только scheme, так что, если надо, могу немного рассказать о семантике вышеозначенных макросов или попытаться накидать аналогичные макросы, скажем, на nemerle.


А можно на Common Lisp? Я вообще не понимаю схемовских макросов. =)
蝸牛そろそろ登れ富士の山
Re[2]: [Этюд]Макрос "or"
От: Mr.Cat  
Дата: 26.04.09 23:28
Оценка:
Здравствуйте, jartur, Вы писали:
J>А можно на Common Lisp? Я вообще не понимаю схемовских макросов. =)

Охх, попробую. Случаем, нет у тебя годной ссылки на "quickstart" по макросам и паттерн-матчингу (syntax-rules — суть паттерн-матчинг для s-выражений) в cl?
Re[3]: [Этюд]Макрос "or"
От: jartur Россия http://jartur.l-square.net;
Дата: 27.04.09 04:24
Оценка:
Здравствуйте, Mr.Cat, Вы писали:


MC>Охх, попробую. Случаем, нет у тебя годной ссылки на "quickstart" по макросам и паттерн-матчингу (syntax-rules — суть паттерн-матчинг для s-выражений) в cl?


Вообще можно здесь прочитать: http://www.gigamonkeys.com/book/macros-defining-your-own.html
Это не то чтобы quickstart по макросам, а кусок неплохой книги для начинающих.

А в общих чертах, там все тупо:
(defmacro name (params*)
body*)

Впрочем по сути макрос — просто функция, которая возвращает форму. При этом ` (backquote) используется для экранирования вичисления, а , и ,@ для их форсирования. Ну например

(defmacro if1 (test true-branch &optional else-branch)
"My super if."
`(cond (,test ,true-branch)
(t ,else-branch)))

Тогда
(if1 (= a b)
(+ a b)
(- a b))
Развернется в (COND ((= A B) (+ A B)) (T (- A B))).

При этом возможен захват переменных и прочие неприятности, потому для имен переменных локальных для макроса нужно использовать gensym. А паттерны можно задавать в строке params. Например

(defmacro for ((a b) &body body)
(let ((a-var (gensym)))
`(do ((,a-var ,a (+ 1 ,a-var)))
((>= ,a-var ,b))
,@body)))

Тогда
(for (1 5)
(+ 1 1)
(+ 2 2))
превращается в (DO ((#:G826 1 (+ 1 #:G826))) ((>= #:G826 5)) (+ 1 1) (+ 2 2))

Если бы мы не использовали gensym, и вместо #:G826 стояло бы SOMEVAR, то в случае наличия SOMEVAR в lexical scope во время вызова макроса, мы бы поимели неприятный эффект. Ладно shadowing, а если бы мы деструктивно присваивали бы что-то SOMEBVAR внутри макроса? Ну понятно, в общем. Никакой гигиены =)

Ну да ладно, лучше в книжке прочитать, там подробнее и понятнее.
蝸牛そろそろ登れ富士の山
Re[4]: [Этюд]Макрос "or"
От: Mr.Cat  
Дата: 28.04.09 20:16
Оценка:
Здравствуйте, jartur, Вы писали:
J>Вообще можно здесь прочитать: http://www.gigamonkeys.com/book/macros-defining-your-own.html
Ммм, точно. Как-то я позабыл про practical common lisp (как-то даже начинал читать, да бросил). Что ж, попробую переписать в cl-макросы...
Re: [Этюд]Макрос "or"
От: Аноним  
Дата: 29.04.09 10:48
Оценка:
Можно подсказку? А то ничего умнее

(define-syntax or
  (syntax-rules ()
    ((_) #f)
    ((_ e1 e2 ...)
     (let ((t e1))
       (if t t (or e2 ...))))))

(define-syntax or1
  (syntax-rules ()
    ((_) #f)
    ((_ e) e)
    ((_ e1 e2 e3 ...)
     (let ((t e1))
       (if t t (or1 e2 e3 ...))))))

(define (if x y z) (error ""))

(or false) ; ошибка
(or1 false) ; нет ошибки

в голову не приходит (
Re[2]: [Этюд]Макрос "or"
От: Mr.Cat  
Дата: 29.04.09 13:27
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Можно подсказку?
Тонкую или не очень?
Re[3]: [Этюд]Макрос "or"
От: Аноним  
Дата: 29.04.09 14:29
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>Здравствуйте, Аноним, Вы писали:

А>>Можно подсказку?
MC>Тонкую или не очень?

Я еще не отчаялся, так что лучше тонкую
Re[4]: [Этюд]Макрос "or"
От: Mr.Cat  
Дата: 29.04.09 14:57
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Я еще не отчаялся, так что лучше тонкую
Ок.
В принципе, недостаток у "неправильного" or довольно безобидный. Однако из-за этого он не удовлетворяет r6rs.
Re[5]: [Этюд]Макрос "or"
От: Аноним  
Дата: 30.04.09 10:22
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>Здравствуйте, Аноним, Вы писали:

А>>Я еще не отчаялся, так что лучше тонкую
MC>) Ок.
MC>В принципе, недостаток у "неправильного" or довольно безобидный. Однако из-за этого он не удовлетворяет r6rs.

Ммм.. Scheme я знаю только в рамках SICP и непродолжительных ковыряний в доках по PLT Scheme. Так что для меня отличия r5rs и r6rs это rocket since
Re: [Этюд]Макрос "or"
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 04.05.09 10:36
Оценка: 44 (2)
Mr.Cat,

Итак, смотрим на макросы (точнее на результат развёртывания их):
  (define-syntax or1
    (syntax-rules ()
      ((_) #f)
      ((_ e1 e2 ...)
       (let ((t e1))
         (if t t 
             (or1 e2 ...))))))
  
  (define-syntax or2
    (syntax-rules ()
      ((_) #f)
      ((_ e) e)
      ((_ e1 e2 e3 ...)
       (let ((t e1))
         (if t t (or2 e2 e3 ...))))))

  (or1 'a 'b 'c 'd)
  ;  =>  
  ;  (let ((t1 'a))
  ;    (if t1 t1 
  ;        (let ((t2 'b)) 
  ;          (if t2 t2 
  ;              (let ((t3 'c)) 
  ;                (if t3 t3 
  ;                    (let ((t4 'd))
  ;                      (if t4 t4 #f))))))))
  
  (or2 'a 'b 'c 'd)
  ;  =>  
  ;  (let ((t1 'a)) 
  ;    (if t1 t1 
  ;        (let ((t2 'b)) 
  ;          (if t2 t2 
  ;              (let ((t3 'c)) 
  ;                (if t3 t3 'd))))))

На первый взгляд, отличия самые минимальные, or1 ну разве что чуть громоздче выглядит. Оки-доки, залез в R6RS draft чтобы узнать, что же такого жуткого написано про "or" в R6RS:

(or <test> ...)
Syntax: The <test>s must be expressions.
Semantics: If there are no <test>s, #f is returned. Otherwise, the <test> expressions are evaluated from left to right until a <test> returns a true value val (see section 5.7) or the last <test> is reached. In the former case, the or expression returns val without evaluating the remaining expressions. In the latter case, the last expression is evaluated and its values are returned.

(or (= 2 2) (> 2 1)) => #t
(or (= 2 2) (< 2 1)) => #t
(or #f #f #f)        => #f
(or '(b c) (/ 3 0))  => (b c)

The or keyword could be defined in terms of if using syntax-rules (see section 11.19) as follows:
(define-syntax or
  (syntax-rules ()
    ((or) #f)
    ((or test) test)
    ((or test1 test2 ...)
     (let ((x test1))
       (if x x (or test2 ...))))))

The last <test> expression is in tail context if the or expression itself is; see section 11.20.


Последняя фраза и наводит на ответ
MC>- Каким недостатком обладает "неправильный" по сравнению с правильным?
Определение or1 не подчиняется требованию хвостовой рекурсии, а or2 — подчиняется.

MC>- Приведите пример кода, который будет по разному вести себя для "неправильной" и "правильной" реализации "or".

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

MC>PS: Все-же этюд касается не только scheme, так что, если надо, могу немного рассказать о семантике вышеозначенных макросов или попытаться накидать аналогичные макросы, скажем, на nemerle.

гм... весьма специфичный этюд, однако.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[2]: [Этюд]Макрос "or"
От: Mr.Cat  
Дата: 04.05.09 15:51
Оценка:
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
MC>>- Каким недостатком обладает "неправильный" по сравнению с правильным?
LCR>Определение or1 не подчиняется требованию хвостовой рекурсии, а or2 — подчиняется.
Именно. Если "правильный" or находится в хвостовой позиции — последний операнд тоже стоит в хвостовой позиции. "Неправильный" or такого не обеспечивает

Хотя здесь отметили, что имплементации могли бы оптимизировать "неправильный" or до состояния "правильного" (но вот, например, chicken не оптимизирует).
Re[2]: [Этюд]Макрос "or"
От: Кодт Россия  
Дата: 05.05.09 13:41
Оценка: +1
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

<>

Глаз сломаешь на этом лиспе!

or1 препятствует хвостовой рекурсии, зато or2 реализует принцип GIGO
(or2 #f #f #f "hello, world!")

вернёт не булевское значение, вместо того, чтобы заругаться на месте.
... << RSDN@Home 1.2.0 alpha 4 rev. 1181>>
Перекуём баги на фичи!
Re[3]: [Этюд]Макрос "or"
От: Mr.Cat  
Дата: 06.05.09 07:51
Оценка:
Здравствуйте, Кодт, Вы писали:
К>
К>;(or2 #f #f #f "hello, world!")
К>;

К>вернёт не булевское значение, вместо того, чтобы заругаться на месте.
Ага.
А вообще, в scheme любое значение, кроме #f, считается истинным с точки зрения if, or, and и т.п.
Re: [Этюд]Макрос "or"
От: GSergey  
Дата: 08.05.09 00:33
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

Вот вариант для SCM Scheme

(defmacro or2 ( . args )
(if (null? args) #f
`(if ,(car args) #t
(or2 ,@(cdr args)))))

он не гигиеничный?
потому что в syntax-rules все никак руки не дойдут разобраться

C>Этюд актуален для любого языка с аппликативным порядком вычисления и макросами, однако в силу происхождения этюда — я предлагаю его в контексте scheme.


MC>В scheme "or" — short-circuit операция, которая принимает произвольное число аргументов. Реализовать "or" можно в виде макроса.

MC>Вот вариант реализация "or":
MC>
MC>(define-syntax or
MC>  (syntax-rules ()
MC>    ((_) #f)
MC>    ((_ e1 e2 ...)
MC>     (let ((t e1))
MC>       (if t t (or e2 ...))))))
MC>

MC>Этот вариант "or" будем считать "неправильным", т.к. он обладает определенным недостатком (с приходом r6rs можно сказать, что двумя).

MC>Вот такой вариант "or" (в нем появляется дополнительное условие) будем считать "правильным":

MC>
MC>(define-syntax or
MC>  (syntax-rules ()
MC>    ((_) #f)
MC>    ((_ e) e)
MC>    ((_ e1 e2 e3 ...)
MC>     (let ((t e1))
MC>       (if t t (or e2 e3 ...))))))
MC>

MC>В связи с этим, предлагаю ответить на два вопроса.

MC>- Каким недостатком обладает "неправильный" по сравнению с правильным?

MC>- Приведите пример кода, который будет по разному вести себя для "неправильной" и "правильной" реализации "or".

MC>PS: Все-же этюд касается не только scheme, так что, если надо, могу немного рассказать о семантике вышеозначенных макросов или попытаться накидать аналогичные макросы, скажем, на nemerle.
Re[2]: [Этюд]Макрос "or"
От: Mr.Cat  
Дата: 08.05.09 00:59
Оценка:
Здравствуйте, GSergey, Вы писали:
GS>Вот вариант для SCM Scheme
GS>он не гигиеничный?
Гигиена — свойство самой макро-системы (syntax-rules, syntactic-closures и т.п.) а не конкретного макроса.
Re[2]: [Этюд]Макрос "or"
От: Аноним  
Дата: 11.05.09 04:21
Оценка:
GS>Здравствуйте, Mr.Cat, Вы писали:

GS>Вот вариант для SCM Scheme


GS>(defmacro or2 ( . args )

GS> (if (null? args) #f
GS> `(if ,(car args) #t
GS> (or2 ,@(cdr args)))))

GS>он не гигиеничный?

Во первых, да, он негигиеничный. Во вторых, он не является аналогом схемовского or, потому как последний возвращает первое не-#f значение, а Ваш or2 возвращает только #t или #f.

GS>потому что в syntax-rules все никак руки не дойдут разобраться

А вот как раз syntax-rules — простой до примитивизма. Там и разбираться то нечего — просто выучить очередной pattern-matching синтаксис (довольно интуитивно-понятный, к слову). syntax-case — гораздо мощнее, гибче и соответственно сложнее в нюансах.
Re[3]: [Этюд]Макрос "or"
От: Аноним  
Дата: 11.05.09 04:26
Оценка:
GS>>Вот вариант для SCM Scheme
GS>>он не гигиеничный?
MC>Гигиена — свойство самой макро-системы (syntax-rules, syntactic-closures и т.п.) а не конкретного макроса.

Автоматическая гигиена — свойство макросистемы, а гигиена — свойство самих макросов (результата их раскрытия)

hygiene condition for macro expansion:
“Generated identifiers that become binding instances in the completely expanded program must only bind variables that are generated at the same transcription step.”

Простой пример: автоматически гигеническая макросистема syntax-case позволяет нарушать гигиену и писать негигенические макросы.
Re[4]: [Этюд]Макрос "or"
От: Mr.Cat  
Дата: 11.05.09 07:02
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Автоматическая гигиена — свойство макросистемы, а гигиена — свойство самих макросов (результата их раскрытия)
Да, пожалуй так будет правильнее.
Re[4]: [Этюд]Макрос "or"
От: Кодт Россия  
Дата: 12.05.09 13:14
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>А вообще, в scheme любое значение, кроме #f, считается истинным с точки зрения if, or, and и т.п.


Зачем тогда отказались от лисповского nil? Чтобы не путать с пустым списком?
И тут же стали путать списки с #t.
... << RSDN@Home 1.2.0 alpha 4 rev. 1207>>
Перекуём баги на фичи!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.