Следующая страница > 1 < [2] [3] [4]

Автор Сообщение

Имя пользователя

Members


Статус

32 сообщений

Где: Vietnam
Род занятий:
Возраст:

#4099   2011-03-30 04:02 GMT+3 часа(ов)      
Решил изучить комон лисп, в общем-то просто для развития, читаю Practical Common Lisp отсюда.
Туплю на таком простом макросе:
(defun report-result (result form)
(format t "~:[FAIL~;pass~] ... ~a~%" result form))
 
(defmacro check (form)
`(report-result ,form ',form))

Насколько я понимаю, обратная кавычка запрещает вычислять целое выражение, а запятой можно разрешить вычислять отдельные части выражения. Простая кавычка делает тоже самое, что и обратная, но для отдельного выражения. Но как понимать кавычку плюс запятую (',form) не пойму.

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#4100   2011-03-30 14:50 GMT+3 часа(ов)      
> ... обратная кавычка запрещает вычислять целое выражение ...
"обратная кавычка", т.е. quasiquote - это макрос, я надеюсь, Вы уже знаете их предназначение.
Может Вам так будет понятнее:
`(report-result ,form ',form) 
==> (list 'report-result form (list 'quote form))

Имя пользователя

Members


Статус

32 сообщений

Где: Vietnam
Род занятий:
Возраст:

#4101   2011-03-30 17:24 GMT+3 часа(ов)      
Спасибо за ответ, но всё ещё не понял... почему/откуда/зачем взялся list?

Опытным путем, вроде, понял. Не доходило до меня, что вариант:
(defmacro check (form)
`(report-result ,form 'form))

Даст в результате:
[9]> (check (= (+ 2 3) 5))
pass ... FORM
NIL

Хотя логику всё-таки не совсем понимаю... В смысле почему "'," в результате даст именно подставленное выражение? Результат запятой и кавычки по отдельности понимаю.

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#4102   2011-03-30 19:32 GMT+3 часа(ов)      
> Хотя логику всё-таки не совсем понимаю... В смысле почему "'," в результате даст именно подставленное выражение?
Напомню, что
'(+ 1 2 3) equal (quote (+ 1 2 3))
`(report-result ,form ',form) equal `(report-result ,form (quote ,form))


quasiquote, в отличие от quote, преобразует SEXP
(report-result ,form ',form)
в
(list 'report-result form (list 'quote form))
используя unquote как маркер.
Проще говоря, quasiquote пофиг на quote, для него это такой же символ как и report-result.

К сожалению, известные мне реализаций CL не позволяют продемонстрировать работу quasiquote. Поэтому я воспользуюсь средствами Рэкета(современный диалект Scheme):
>  (expand/step-text #'`(report-result ,form ',form))
Macro transformation
`(report-result ,form ',form)
==>
(list:1 'report-result form (list:1 'quote form))
...

Имя пользователя

Members


Статус

32 сообщений

Где: Vietnam
Род занятий:
Возраст:

#4104   2011-03-30 23:31 GMT+3 часа(ов)      
Большое спасибо, разобрался.

ander-skirnir

Members


Статус

227 сообщений
http://lisper.ru
Где: Ukraine
Род занятий: `'`,`',`',
Возраст: 28

#4105   2011-03-31 04:14 GMT+3 часа(ов)      
> К сожалению, известные мне реализаций CL не позволяют продемонстрировать работу quasiquote.

Все вменяемые позволяют, это в стандарте есть:
(let ((*print-pretty* nil))
(print '`(report-result ,form ',form)))
=>
(SB-IMPL::BACKQ-LIST (QUOTE REPORT-RESULT)
FORM (SB-IMPL::BACKQ-LIST (QUOTE QUOTE) FORM))


Правда, надо отметить, оно без точечек распечатало

отредактировал(а) ander-skirnir: 2011-03-31 04:21 GMT+3 часа(ов)

Имя пользователя

Members


Статус

32 сообщений

Где: Vietnam
Род занятий:
Возраст:

#4106   2011-03-31 06:13 GMT+3 часа(ов)      
Кстати, вопрос насчёт стандарта - поиск по нему есть? Или только индекс/оглавление?
Через гугл искать умею, если что.

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#4107   2011-03-31 13:49 GMT+3 часа(ов)      
> Все вменяемые позволяют, это в стандарте есть: ...
Правда, надо отметить, оно без точечек распечатало

Так он распечатал не совсем то, что нужно
Если я правильно понимаю, SB-IMPL::BACKQ-LIST является встроенным маркером, т.е. обрабатывается ридером
'(SB-IMPL::BACKQ-LIST 1 2 3)
=>
`(,1 ,2 ,3)
Прочитав HyperSpec, я обнаружил, что quasiquote(backquote) обрабатывается на уровне ридера, причем реализации сами вправе выбирать как им лучше реализовать обработку backquote. Поэтому вменяемость тут не причем, просто SBCL имеет внутреннее представление backquote, а другие нет - это их право.

На Ваш взгляд, кроме SBCL есть еще "вменяемые" реализации?

ander-skirnir

Members


Статус

227 сообщений
http://lisper.ru
Где: Ukraine
Род занятий: `'`,`',`',
Возраст: 28

#4110   2011-04-01 01:48 GMT+3 часа(ов)      
> quasiquote(backquote) обрабатывается на уровне ридера
Конечно, это же ридер-макрос...

> SB-IMPL::BACKQ-LIST является встроенным маркером, т.е. обрабатывается ридером

который раскрывается в s-expr с SB-IMPL::BACKQ-LIST, который является обыкновенной функцией.

> => `(,1 ,2 ,3)

Это всё pretty-printer, опять же.

> реализации сами вправе выбирать как им лучше реализовать обработку backquote
Да, просто по-другому нормально реализовать backquote (не преобразуя его на этапе чтения в s-expr) не получится.

> На Ваш взгляд, кроме SBCL есть еще "вменяемые" реализации?
allegro-cl, lisp-works, clozure-cl.
Последний делает это так:
(let ((*print-pretty* nil))
(print '`(report-result ,form ',form)))
=>
(LIST* 'REPORT-RESULT (LIST* FORM (LIST (LIST* 'QUOTE (LIST FORM)))))

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#4112   2011-04-01 18:36 GMT+3 часа(ов)      
> Конечно, это же ридер-макрос... который раскрывается в s-expr с SB-IMPL::BACKQ-LIST, который является обыкновенной функцией.
То что SB-IMPL::BACKQ-LIST функция, я понял с самого начала. А как Вы определили, что backquote именно ридер-макрос? Или может это терминология такая (любой идентификатор(маркер) используемый ридером на этапе создания АСД - ридер-макрос)?

> Да, просто по-другому нормально реализовать backquote (не преобразуя его на этапе чтения в s-expr) не получится.

Полчаса работы(но не тестирования):
#lang dynamic-racket
 
(require racket/match)
 
(defmacro backquote (s-exp)
(letrec ([unquote?
(lambda(s-exp)
(and (pair? s-exp)
(eq? (car s-exp) 'unquote)
(pair? (cdr s-exp))
(unless (null? (cddr s-exp))
(raise s-exp))))]
[unquote-splicing?
(lambda(s-exp)
(and (pair? s-exp)
(eq? (car s-exp) 'unquote-splicing)
(pair? (cdr s-exp))
(unless (null? (cddr s-exp))
(raise s-exp))))]
[backq-list
(lambda (s-exp)
(match s-exp
[(list-rest a ... (? unquote? b) c)
(if (null? c)
(list 'append
(backq-list a)
(list 'list (cadr b)))
(list 'append
(backq-list a)
(list 'list (cadr b))
(backq-list c)))]
[(list-rest a ... (? unquote? b))
(list 'append (backq-list a) (cadr b))]
[(list-rest a ... (? unquote-splicing? b) c)
(if (null? c)
(list 'append
(backq-list a)
(cadr b))
(list 'append
(backq-list a)
(cadr b)
(backq-list c)))]
[(list-rest a ... (? unquote-splicing? b))
(raise s-exp)]
[_
(cond
[(or (symbol? s-exp)
(null? s-exp))
(list 'quote s-exp)]
[(pair? s-exp)
(if (list? s-exp)
(cons 'list
(map backq-list s-exp))
(cons 'list*
(let loop ([lst s-exp])
(if (pair? lst)
(cons (backq-list (car lst))
(loop (cdr lst)))
(list (backq-list lst))))))]
[else
s-exp])]))])
(backq-list s-exp)))
Алгоритм, конечно, не самый оптимальный, ну да ладно.
> (expand/macro
'(backquote (1 (2 ,7))))
'(list 1 (append (list 2) (list 7)))
> (expand/macro
'(backquote (1 2 ,@(list 3) 4 ,@(list 5))))
'(append (append (list 1 2) (list 3) (list 4)) (list 5))
> (expand/macro
'(backquote (report-result ,form ',form)))
'(append (list 'report-result)
(list form) (list (append (list 'quote) (list form))))
> (expand/macro
'(defmacro atom? (s-exp)
(backquote (not (pair? ,s-exp)))))
'(set! atom?
(first-class-macros
(lambda (s-exp)
(call/cc
(lambda (return)
(list 'not (append (list 'pair?) (list s-exp))))))))
> (defmacro atom? (s-exp)
(backquote (not (pair? ,s-exp))))
> (expand/macro '(atom? '(5)))
'(not (pair? '(5)))

Исходники dynamic-racket:
svn export http://srcc.googlecode.com/svn/trunk/dynamic-racket dynamic-racket

отредактировал(а) misha: 2011-04-01 18:54 GMT+3 часа(ов)

ander-skirnir

Members


Статус

227 сообщений
http://lisper.ru
Где: Ukraine
Род занятий: `'`,`',`',
Возраст: 28

#4116   2011-04-02 01:55 GMT+3 часа(ов)      
> А как Вы определили, что backquote именно ридер-макрос?
Ну, например, так:
> Backquote ` (reader macro)
Но если глубоко покопать, то становится понятно, что ничем иным он быть не может.


> Полчаса работы(но не тестирования):..

Очень круто, конечно, но я несколько про другое. У тебя тут ведь всё - и так s-expr'ы. И до экспанда и после. Я имел ввиду, что из этого можно сделать вывод что оно вроде и необязательно должно в s-expr трансформироваться. Но чтобы сохранить списочную семантику, преобразовывая беквот в какую-нибудь другую структуру данных, придётся приложить невероятные и неоправданные усилия, если это вообще возможно. А так как единственно вменяемый, простой и удобный способ - преобразование в s-expr, любая вменяемая же реализация CL позволит глянуть результат этой трансформации.

> dynamic-racket
Посмотрел, интересно, мощно, но многие вещи, за которые коммон-лисперы любят коммон-лисп, снаружи не видно, и потому любители схем о них не догадываются Судя по себе, заметил, что одно из важнейших для меня свойств - тотальная (почти) первоклассность. Чтобы не было существенной разницы, пишешь ты программу в файле, а потом компилируешь, или пишешь всё время в репле. Лично я сразу evalю каждую написанную топлевельную форму, и с ростом программы переevalиваю старые (например, написал новую функцию, хочу экспортнуть её из текущего пакета - просто дописываю её имя в раздел :export формы defpackage, и жму C-x/e). То есть, фактически, вся разработка целиком происходит в рантайме и потому для меня очень важно, чтобы не было (или хотя бы было незаметно мало) специальной статической магии компилятора, опирающейся на готовые целые исходники. Насколько я знаю, в Racket этого полно, особенно с фазами и модулями.
А еще, для такой модели разработки очень плохо подходит глобальный лексический скоупинг. Например, у тебя вот есть
(defmacro defun (name formals expr . body)
(eval `(define ,name #f))
`(set! ,name (lambda ,formals
(call/cc
(lambda (return)
,expr . ,body)))))

Допустим, я написал функцию foo1, евальнуль, протестировал, а потом объявил новый пакет и написал в нём foo2,foo3,foo4, внутри каждой из которой есть вызов предыдущей - и тут внезапно оказалось, что я хочу слегка изменить foo1. Я её корректирую, евалю, и мне не нужно перееваливать все остальные, потому что функции скоупаются динамически. Racket я знаю плохо, но интуиция мне подсказывает, что здесь это работает иначе. Сам бы завёл да посмотрел, но чувствую, это будет не так просто, потому как-нибудь попозже.

отредактировал(а) ander-skirnir: 2011-04-02 02:04 GMT+3 часа(ов)

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#4117   2011-04-02 22:38 GMT+3 часа(ов)      
> Но если глубоко покопать, то становится понятно, что ничем иным он быть не может.
У меня сложилось впечатление, что любой идентификатор(маркер) используемый ридером на этапе создания АСД является ридер-макросом.

> Я имел ввиду, что из этого можно сделать вывод что оно вроде и необязательно должно в s-expr трансформироваться.
Там говорится о "форме" конечного s-exp, т.е. результатом может быть любое адекватное s-exp.

> Посмотрел, интересно, мощно, но многие вещи, за которые коммон-лисперы любят коммон-лисп, снаружи не видно, и потому любители схем о них не догадываются
Существует и обратное утверждение

> Судя по себе, заметил, что одно из важнейших для меня свойств - тотальная (почти) первоклассность.
Жаль что в CL отсутствуют first-class-макросы, но их легко можно реализовать
Они прикольно работают:
> (defmacro m (a b) `(list ,a ,b))
> (define m2 m)
> (expand/macro/trace '(m2 1 2))
Macro transformation 1
(list 1 2)
'(list 1 2)
> (expand/macro '(m2 1 2))
'(list 1 2)


> Насколько я знаю, в Racket этого полно, особенно с фазами и модулями.
Фазы существуют только во время компиляции модуля. В рантайме только одна фаза макротрансформации(как и у Лиспа), хотя из-за специфической работы макросов могут появиться промежуточные стадии как макротрансформации, так и предварительной компиляции некоторых частей s-exp.
Немного о модулях.
Экземпляр модуля, как и экземпляр класса, можно представить как лямбду специального вида. Чтобы определить модуль используется макрос module, который и осуществляет все эти макрофазы. А экземпляр модуля имеет всего одну специальную фазу (в которой вычисляются определения используемые макросами) осуществляемую во время загрузки определений из модуля посредством require, тогда и происходит вычисление тела модуля. Кстати, экземпляр модуля, как и функция, возвращает значение!
> (module test racket
(begin-for-syntax
(displayln "Hey!"))
 
(define-syntax (as so) (displayln "Oops!") #'1234)
 
as)
Hey!
Oops!
Hey!
Hey!
> (module test2 racket 1)
> (require 'test 'test2)
Hey!
1234
1
> (require 'test 'test2)
> (module test2 racket 1) ; повторное определение модуля
1
 

Изменить значения экспортируемых определений способны только функции определенные в том же модуле, что и экспортируемые определения. Т.е. импортируемые определения невозможно изменить посредством set! (для него они константы).

отредактировал(а) misha: 2011-04-02 23:09 GMT+3 часа(ов)

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#4118   2011-04-03 00:04 GMT+3 часа(ов)      
> А еще, для такой модели разработки очень плохо подходит глобальный лексический скоупинг.
Он не глобальный, т.к. у Рэкета используются пространства имен. Если eval-у не указать пространство имен, то по умолчанию используется текущее.

> Допустим, я написал функцию foo1, евальнуль, протестировал, а потом объявил новый пакет и написал в нём foo2,foo3,foo4, внутри каждой из которой есть вызов предыдущей - и тут внезапно оказалось, что я хочу слегка изменить foo1. Я её корректирую, евалю, и мне не нужно перееваливать все остальные, потому что функции скоупаются динамически.
Для set! импортируемые определения являются константами, и таким образом в рантайме обеспечивается примитивная защита от подмены значений импортируемых определений. Но когда код предполагает изменение какого-либо значения(параметра) используется "параметр" (по сути это обертка в виде функции).
#lang dynamic-racket
 
(module test1 dynamic-racket
(provide (all-defined-out))
 
(defun _foo1_ (x) x)
(define-for-provide _foo1_ (make-parameter _foo1_))
; или просто (define-for-provide _foo1_ (make-parameter (lambda (x) x)))
 
(defmacro foo1 (x) `((_foo1_) ,x))
(define-for-provide foo1)
 
; Логичнее было бы определить так
;; (for-provide
;; (define (foo2 x)
;; (printf "x = ~a\n" x))
;; (define (set!-foo2 v)
;; (set! foo2 v)))
; ибо defun не для этого создавался:)
(define-for-provide foo2 #f) ; все из-за реализации модуля
(defun foo2 (x) (printf "x = ~a\n" x))
(for-provide (set! foo2 foo2))
 
(defun set!-foo2 (v)
(set! foo2 v))
(define-for-provide set!-foo2))
 
(module test2 dynamic-racket
(require 'test1)
(provide (all-defined-out))
 
(defun foo3 (x)
(foo1 x))
 
(defun foo4 (x)
(foo2 x))
 
(define-for-provide foo3)
(define-for-provide foo4))
 
> (require 'test2 'test1)
> (foo3 1)
1
> (dynameterize ([_foo1_ (lambda(x) (displayln (add1 x)))])
(foo3 1))
2
> (foo3 1)
1
> (_foo1_ (lambda(x) (add1 x)))
> (foo3 1)
2
> (foo4 10)
x = 10
> (set!-foo2 add1)
> (foo4 10)
11
Как Вы наверняка заметили, dynamic-racket с трудом влезает в модули Рэкета.

отредактировал(а) misha: 2011-04-03 13:45 GMT+3 часа(ов)

ander-skirnir

Members


Статус

227 сообщений
http://lisper.ru
Где: Ukraine
Род занятий: `'`,`',`',
Возраст: 28

#4128   2011-04-05 03:07 GMT+3 часа(ов)      
> У меня сложилось впечатление, что любой идентификатор(маркер) используемый ридером на этапе создания АСД является ридер-макросом.
В CL всего два вида токенов - символы и числа. Ридер-макросами могут быть произвольные единичные символы, либо dispatch-комбинации из двух символов (но при желании, из первого можно слепить что-угодно). Им просто назначаются функции чтения, которые делают с потоком что-угодно в разумных пределах
Вот пример гибкости и hackability ридера:
(list
(let ((*readtable* (copy-readtable)))
(set-macro-character #\a (constantly 1))
#1=(eval (read-from-string "(list 'aaaa 'a)")))
#1#)
=>
((1 1 1 1 1) (AAAA A))


> Существует и обратное утверждение
Не сомневаюсь Просто каков бы racket ни был крут и прогрессивен, коммон-лиспер не найдёт там родного духа непрерывного экспериментаторства (речь идёт о написании любых программ на racket, а не о самом racket и его начинке), не будет ощущать итеративное эволюционирование живой, самодостаточной, самоопределённой системы. В CL получилась уникальная связка rapid-prototyping, iterative-development и exploration-programming, такая, что весь язык гармонично в неё вписывается, и больше нигде ничего подобного нет.

> в CL отсутствуют first-class-макросы
Да не, всё на месте, просто в CL же `пространства имён` хитрые:
(defmacro m (a b)
`(list ,a ,b))
 
(setf (macro-function 'm2)
(macro-function 'm))
 
(macroexpand '(m2 1 2))
=>
(list 1 2)


> Он не глобальный

Ну да, это я некорректно мысль изложил. Я имел ввиду скоупинг define. В CL лексически скоупаются практически только let-биндинги (let[*]/flet/labels/macrolet/symbol-macrolet), не помеченные декларацией :special. И мне такой подход нравится.

> когда код предполагает изменение какого-либо значения(параметра) используется "параметр" (по сути это обертка в виде функции).
> Кстати, экземпляр модуля, как и функция, возвращает значение!

Что мне нравится в схемах и racket (из того, что я поверхностно сумел заметить) - так это использование функций на-всю-катушку Недавно вот наткнулся на какой-то srfi, где был описан generalized-set, который производит диспатч по функциональным значениям, а не по синтаксису, за счёт чего является первоклассным, в отличии от setf, но жутко тормозным

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#4130   2011-04-05 21:17 GMT+3 часа(ов)      
> Вот пример гибкости и hackability ридера:
Ответный пример:
#lang dynamic-racket
> (defun const (v)
(lambda (char port src line col pos)
(printf "char = ~s; src = ~s; line = ~s; col = ~s; pos = ~s;\n"
char src line col pos)
v))
> (dynameterize ([current-readtable
(make-readtable (current-readtable)
#\a 'terminating-macro (const 1))])
(eval (read (open-input-string "(list 'aaaa 'a)"))))
char = #\a; src = #f; line = #f; col = #f; pos = 8;
char = #\a; src = #f; line = #f; col = #f; pos = 9;
char = #\a; src = #f; line = #f; col = #f; pos = 10;
char = #\a; src = #f; line = #f; col = #f; pos = 11;
char = #\a; src = #f; line = #f; col = #f; pos = 14;
'(1 1 1 1 1)
> (defun backq (char port src line col pos)
((first-class-macros-closure backquote) (read port)))
> (dynameterize ([current-readtable
(make-readtable (current-readtable)
#\` 'terminating-macro backq)])
(read (open-input-string "`(1 2 ,(list 3) . 4)")))
'(append (list 1 2) (list (list 3)) 4)

> Просто каков бы racket ни был крут и прогрессивен, коммон-лиспер не найдёт там родного духа непрерывного экспериментаторства (речь идёт о написании любых программ на racket, а не о самом racket и его начинке), не будет ощущать итеративное эволюционирование живой, самодостаточной, самоопределённой системы.
Просто не стоит лезть в чужой огород со своим уставом К Рэкету необходимо привыкнуть.

> В CL получилась уникальная связка rapid-prototyping, iterative-development и exploration-programming, такая, что весь язык гармонично в неё вписывается, и больше нигде ничего подобного нет.
А может и есть, кто его знает

> Да не, всё на месте, просто в CL же `пространства имён` хитрые:
Ну, это же не первоклассность.
> (expand/macro `(,(first-class-macros add1) 5))
6
> x
reference to an identifier before its definition: x
> y
reference to an identifier before its definition: y
> (y 0
((macrolambda params
(eval `(define x (first-class-macros ,recurse)))
(eval '(define y x))
`(list . ,params))
1 2)
(x 3 4)
5)
'(0 (1 2) (3 4) 5)
> x
#<first-class-macros>
> y
#<first-class-macros>


> Я имел ввиду скоупинг define. В CL лексически скоупаются практически только let-биндинги (let[*]/flet/labels/macrolet/symbol-macrolet), не помеченные декларацией :special. И мне такой подход нравится.
Кстати, поддержка define скорее дань традиции, чем необходимость. Большинство нормальных реализаций Схемы имеют настраиваемый set!, т.е. позволяют эмулировать поведение setq.
Например,
> (compile-allow-set!-undefined #t)
> (y ((macrolambda params
(set! x (first-class-macros recurse))
(set! y x)
`(list . ,params))
1 2)
(x 3 4))
'((1 2) (3 4))

megamanx

Members


Статус

307 сообщений

Где: Russia
Род занятий:
Возраст:

#4131   2011-04-06 00:20 GMT+3 часа(ов)      
ВОТ пример гибкости и hackability:
#! /usr/bin/perl
package mypack;
sub TIESCALAR {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = {};
$self -> {STRING} = '';
bless($self, $class);
return $self;
}
sub STORE {
$_[0] -> {STRING} = join(' ', reverse(@{$_[1]}));
}
sub FETCH {
sprintf $_[0]->{STRING}, <STDOUT>;
}
package main;
my $bucks;
tie $bucks, "mypack";
$bucks = [qw('world!' . ' ' . 'hello' print)];
eval $bucks;

#!/usr/bin/perl -w
use strict;
 
my $even = \&even;
my $odd = \&odd;
 
print trampoline($even, 10001);
 
sub trampoline{
my ($fun, @args) = @_;
return $fun if ref($fun) ne 'CODE';
($fun, @args) = $fun->(@args);
while (ref($fun) eq 'CODE'){
($fun, @args) = $fun -> (@args);
}
return $fun;
}
 
sub even{
my ($n) = shift;
return "true" if $n == 0;
return($odd, --$n);
}
 
sub odd{
my ($n) = shift;
return "false" if $n == 0;
return ($even, --$n);
}

Гибкость - это вопрос условный. Смотря что сгибать.
P.S. тоже захотелось померяться п...

отредактировал(а) megamanx: 2011-04-07 00:12 GMT+3 часа(ов)
I wish I'd made you angry earlier

Имя пользователя

Members


Статус

32 сообщений

Где: Vietnam
Род занятий:
Возраст:

#4132   2011-04-06 22:46 GMT+3 часа(ов)      
Ещё один вопрос.
(defvar *test* '((1 2)(3 4)(1 3)(2 2)(3 4 5)))
 
(count '(1 2) *test*) => 0

Почему ноль? И как это записать правильно?

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#4133   2011-04-06 23:46 GMT+3 часа(ов)      
> Почему ноль? И как это записать правильно?
По умолчанию в качестве предиката используется eq.
> (count '(1 2) *test* :test 'equal)
1

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#4134   2011-04-06 23:51 GMT+3 часа(ов)      
> ВОТ пример гибкости и hackability:
...
P.S. тоже захотелось померяться п...

hackability присутствует) Но где же тут гибкость?

Имя пользователя

Members


Статус

32 сообщений

Где: Vietnam
Род занятий:
Возраст:

#4137   2011-04-07 04:55 GMT+3 часа(ов)      
misha
По умолчанию в качестве предиката используется eq.
Спасибо.
А почему в документации про это ни слова? Или это стандартная функция сравнения и она используется по умолчанию везде?

Имя пользователя

Members


Статус

32 сообщений

Где: Vietnam
Род занятий:
Возраст:

#4140   2011-04-08 17:23 GMT+3 часа(ов)      
А ещё прочел, что функция APPEND возвращает список, который "использует" последний аргумен. С терминологией у меня плохо, так что за это не пинайте. Вот на примере:
(defparameter *t1* (list 1 2))
(defparameter *t2* '(3 4))
(defparameter *t3* (append *t1* *t2*))

Теперь если изменить *t2*, то и *t3* изменится. Ок, допустим это правильно и так и надо. А как создать новый список не связанный с другими?
*t2* => (3 4)
*t3* => (1 2 3 4)
 
(setf (first *t2*) 10)
 
*t2* => (10 4)
*t3* => (1 2 10 4)
 


А если изменить *t2* "целиком" ( (setf *t2* (list 3 4)) ), то *t3* не меняется...

И ещё мелкий вопрос - как лучше/правильнее:
(defparameter *t1* (list 1 2))

или
(defparameter *t1* '(1 2))

Или абсолютно не важно?

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#4141   2011-04-08 22:20 GMT+3 часа(ов)      
> А почему в документации про это ни слова? Или это стандартная функция сравнения и она используется по умолчанию везде?
eq является самым быстрым предикатом.

> А ещё прочел, что функция APPEND возвращает список, который "использует" последний аргумен. ... А если изменить *t2* "целиком" ( (setf *t2* (list 3 4)) ), то *t3* не меняется...
Попробуйте реализовать APPEND самостоятельно.

> А как создать новый список не связанный с другими?
См. COPY-LIST. Эту функцию также попробуйте реализовать самостоятельно.

> Или абсолютно не важно?
А как Вы думаете?

Имя пользователя

Members


Статус

32 сообщений

Где: Vietnam
Род занятий:
Возраст:

#4145   2011-04-09 03:37 GMT+3 часа(ов)      
Цитата
misha :
eq является самым быстрым предикатом.
Да меня больше смутило, что об этом явно не сказано... Может торможу, но документация, например, мсдн как-то более подробна(привычна), пусть и имеет свои особенности.

Цитата
Попробуйте реализовать APPEND самостоятельно.
См. COPY-LIST.
Спасибо, я уже разобрался. (:
Просто не дочитав главу до конца начал экспериментировать... потом пришло понимание как и почему это работает так.

Цитата
А как Вы думаете?
Догадываюсь, что с точки зрения результата и производительности разницы нет. Но ещё интересует "как принято".

Возможно, снова забегаю вперёд, но интересуют два таких вопроса:
1. Перегрузка функций. В "practical common lisp" есть что-то про мультиметоды, но это уже в контексте ООП, да и немного не то ведь. А ведь всякие функции типа remove или substitute как-то проверяют полученное значение?
Это дальше в книге будет? Если нет, то можно ссылку где почитать?
2. Сейчас использую репл, но лисп ведь и компилироваться может? Вот интересен следующий момент - какая должна быть "главная функция"? Ну то есть по аналогии с С - там main. Или в лиспе и это мега иначе?

ander-skirnir

Members


Статус

227 сообщений
http://lisper.ru
Где: Ukraine
Род занятий: `'`,`',`',
Возраст: 28

#4146   2011-04-09 05:31 GMT+3 часа(ов)      
> Ну, это же не первоклассность.
Да. Я думал, они и в racket не в строгом смысле первоклассные, но потом увидел
> (y 0 ((macrolambda params ...
Круто, конечно, очень, но это уже гораздо больше, чем макросы в каноническом понимании

> функция APPEND возвращает список, который "использует" последний аргумен
> (append *t1* *t2*))
> Теперь если изменить *t2*, то и *t3* изменится. Ок, допустим это правильно и так и надо. А как создать новый список не связанный с другими?

(append *t1* *t2* nil)
 

> А ведь всякие функции типа remove или substitute как-то проверяют полученное значение?
Да, проверяют. Динамически. И перегрузки динамические - мультиметоды.
Статических перегрузок нет, можно велосипедить на макросах и самописных типовыводилках, типопроверялках и так далее. Но это не очень вписывается в идеологию.

> это уже в контексте ООП
Да, но ООП в Лиспе очень отличается от того, к чему ты, скорее всего, привык ( исхожу из упоминания msdn : )

> Или абсолютно не важно?
Разница есть, но пока этим заморачиваться не обязательно. '(...) - константное выражение, (list ...) - нет. Константные данные мутировать не рекомендуется.

> Сейчас использую репл, но лисп ведь и компилироваться может?
Например, если ты используешь sbcl, то у тебя каждое введённое в repl выражение компилируется перед исполнением. Это кажется непривычным после языков, в которых сначала пишешь, потом компилируешь. Это называется инкрементальная компиляция (только в данном случае не в первом смысле, а во втором (там, где interactive-programming)). Одна из наиболее практичных фич Лиспа - программирование-на-ходу. На Сommon-Lisp все только так и пишут, потому что это очень удобно и быстро, особенно если использовать emacs+slime. А когда программа целиком написана, можно либо скомпилировать её целиком заново, либо просто сохранить образ-fasl (или exe'шник, если надо) рантайма с помощью (save-lisp-and-die).

> Вот интересен следующий момент - какая должна быть "главная функция"?
Вот это уже диктуется конкретной реализацией. Вот пример хелловорлда на sbcl:
(defun hello-world ()
(princ "hello-world!")
(quit))
 
(push #'hello-world
sb-ext:*init-hooks*)
 
(save-lisp-and-die "hello-world.exe"
:executable t)

отредактировал(а) ander-skirnir: 2011-04-09 05:51 GMT+3 часа(ов)

Имя пользователя

Members


Статус

32 сообщений

Где: Vietnam
Род занятий:
Возраст:

#4147   2011-04-09 07:29 GMT+3 часа(ов)      
Цитата
misha :
Попробуйте реализовать APPEND самостоятельно.
Попробовал, получилось вот что:
(defun true-append(&rest lists)
(let ((result (list nil)))
(dolist (list-val lists)
(dolist (val list-val)
(setf result (cons val result))))
(reverse result)))

Работает, идею я, вроде, понял, но если есть какие-то замечания, то рад буду выслушать.


Цитата
ander-skirnir :
(append *t1* *t2*))
Вот это просто и круто. (:

Цитата
Да, проверяют. Динамически. И перегрузки динамические - мультиметоды.
Да, но ООП в Лиспе очень отличается от того, к чему ты, скорее всего, привык ( исхожу из упоминания msdn : )
Ну это я узнал когда гуглил. Просто не понял, что это относится не только к "классам" (да я привык к языкам, где класс - это отдельная сущность, потому и решил для расширения кругозора что-то "необычное" попробовать), а не ко всем типам.
Плюс как-то совсем не ожидал, что мультиметоды могут и один параметр принимать - какие же они тогда мульти?)

Цитата
Например, если ты используешь sbcl, то у тебя каждое введённое в repl выражение компилируется перед исполнением. Это кажется непривычным после языков, в которых сначала пишешь, потом компилируешь.
Использую GNU CLISP 2.49 (2010-07-07), но думаю это пока не важно. У sbcl статус (под винду) "port in progress" так что использовать не решился.
Как раз экзешник интересовал, почему-то ожидал, что это будет в стандарте...
В остальном всё понятно, спасибо.

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#4148   2011-04-09 14:43 GMT+3 часа(ов)      
> Работает, идею я, вроде, понял, но если есть какие-то замечания, то рад буду выслушать.
Похоже Вы не совсем разобрались с append. Можете взглянуть на мой велосипедный алгоритм:
(defun %append (&rest lists)
(cond
((null lists) nil)
((null (cdr lists)) (car lists))
((null (cddr lists))
(reduce 'cons (car lists)
:initial-value (cadr lists)
:from-end t))
(t
(%append (car lists) (apply '%append (cdr lists))))))
 
> (%append '(1 2 3) 4)
(1 2 3 . 4)
 
> (%append '(1 2 3) '(4))
(1 2 3 4)
 
> (%append '(1 2 3))
(1 2 3)
 
> (%append 1)
1

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#4149   2011-04-09 15:19 GMT+3 часа(ов)      
> Да. Я думал, они и в racket не в строгом смысле первоклассные, но потом увидел
> (first-class-macros? (macrolambda x 1))
#t

> Круто, конечно, очень, но это уже гораздо больше, чем макросы в каноническом понимании
Если необходим классический механизм, тогда нужно установить параметр classic-eval в #t. Классический механизм гораздо быстрее используемого по умолчанию.

Имя пользователя

Members


Статус

32 сообщений

Где: Vietnam
Род занятий:
Возраст:

#4158   2011-04-11 07:51 GMT+3 часа(ов)      
А ещё вопрос, вот тут написано, что copy-list не создаёт новые cons-ячейки для подсписков (списков вложенных в список).
Я это понял так, что такие подсписки у старого и нового списка будут общие. И если изменить один, то изменится и второй. Но что-то пробовал - не получилось.

Значит я не так понял? Или криво проверял?
В общем надо ли использовать copy-tree чтобы именно скопировать данные, а не разделять.

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#4163   2011-04-11 16:52 GMT+3 часа(ов)      
> Значит я не так понял? Или криво проверял?
А как Вы проверяли?

Имя пользователя

Members


Статус

32 сообщений

Где: Vietnam
Род занятий:
Возраст:

#4167   2011-04-11 21:13 GMT+3 часа(ов)      
Криво проверял, как оказалось. Вопрос снимается. (:
Значит надо использовать copy-tree...
Эта тема закрыта, публикация новых сообщений недоступна.


Онлайн :

0 пользователь(ей), 39 гость(ей) :




Реклама на сайте: