LINUX.ORG.RU

Вычисления при компиляции в Racket

 ,


1

2

Есть ли простой путь замены CL-овского #. ?

Например, кусок кода

(case ftype
                   ((#.(keyword->g-type :enum)
                       #.(keyword->g-type :flags))
                    (convert-to-foreign value (g-type->lisp type)))
                   (#.(keyword->g-type :double)
                      (coerce value 'double-float))
                   (#.(keyword->g-type :float)
                      (coerce value 'single-float))
                   ((#.(keyword->g-type :int)
                       #.(keyword->g-type :uint)
                       #.(keyword->g-type :long)
                       #.(keyword->g-type :ulong)
                       #.(keyword->g-type :int64)
                       #.(keyword->g-type :uint64)) (round value))
                   (t value))

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

Могу вручную выполнить (keyword->g-type :uint), (keyword->g-type :long) и подставить в код результаты. Но будет пачка «магических чисел» в коде. Причём, если в следующей версии будут другие числа у ключевых слов, придётся как-то искать все места использования.

Что посоветуете?

★★★★★

Нашёл.

monk ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Предложили красивее

(require (for-syntax racket/syntax))

(define-syntax (with-compile-time-unsyntax stx)
   (syntax-case stx ()
     [(wctu form ...)
      (syntax-local-introduce
       (syntax-local-eval #'(quasisyntax (begin form ...))))]))

И пример использования:

(begin-for-syntax
   (define the-symbol 'apple))

(with-compile-time-unsyntax
  (define (f x)
    (case x
      ((#,the-symbol) 'yes)
      (else 'no))))

(f 'apple) ;; => 'yes
(f 'pear) ;; => 'no

monk ★★★★★
() автор топика
Ответ на: комментарий от anonymous

А если предположить вариант с reader-macro, то мне не совсем ясно, как его включать в Racket.

Вот сделал

(define parse-sharp-dot
  (case-lambda
    [(ch port)
     ; ‘read' mode
     (eval (read/recursive port #f))]
    [(ch port src line col pos)
     ; ‘read-syntax' mode
     (datum->syntax
      #f
      (eval (read-syntax/recursive src port #f))
      (let-values ([(l c p) (port-next-location port)])
        (list src line col pos (and pos (- p pos)))))]))

(define sharp-dot
  (make-readtable (current-readtable)
                  #\. 'dispatch-macro parse-sharp-dot))

В REPL даже работает:

> (current-readtable sharp-dot)
> (define x 2)
> (define (test)
    (case 3 [(#.(+ x 1)) 'ok] [else 'fail]))
> (test)
'ok

А вот если эти же 4 строки ввести просто в программу, то ругается, что #. не определён.

Если даже вынести readtabl отдельный файл и добавить read и read-syntax для определения lang:

  (provide (rename-out [inner-read read] 
                       [inner-read-syntax read-syntax]))

  (define (inner-read ch port)
    (parameterize ([current-readtable sharp-dot])
      (read ch port)))
  
  (define (inner-read-syntax ch port)
    (parameterize ([current-readtable sharp-dot])
      (read-syntax ch port)))

Всё равно не работает

#lang racket
(define x 2)
#reader"reader.rkt" 
(define (test)
  (case 3 [(#.(+ x 1)) 'ok] [else 'fail]))

;; => test-reader.rkt:5:15: +: unbound identifier; also, no #%app syntax transformer is bound at: + in: (+ x 1)

monk ★★★★★
() автор топика
Последнее исправление: monk (всего исправлений: 1)
Ответ на: комментарий от monk

Для евала надо указать корректный неймспейс. Смотри документацию по неймспейсам и евалу.

anonymous
()
Ответ на: комментарий от monk

Да, прикольно. Но лучше тогда перегрузить unsyntax, по-моему:

(define-syntax (unsyntax stx)
  (syntax-case stx ()
    [(_ form) #`#,(syntax-local-eval #'form)]))
Ну или внутри with-формы через let-syntax. Или через параметры (лучше).

anonymous
()
Ответ на: комментарий от anonymous

А, там же внутри кейза. Тогда через перегрузку unsyntax не выйдет.

anonymous
()

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

anonymous
()
Ответ на: комментарий от anonymous

надо указать корректный неймспейс

А как указать неймспейс того места, в котором вызывается readmacro? В примере

#lang racket
(define x 2)
#reader"reader.rkt" 
(define (test)
  (case 3 [(#.(+ x 1)) 'ok] [else 'fail]))
я могу заставить увидеть +, а вот как заставить увидеть (define x 2) ?

monk ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Интересно, кстати, было бы посмотреть на макросистему, которая раскрывала бы бы макросы не снаружи вовнутрь, а изнутри наружу, если иное (задержка экспанда формы) не указано.

Так реализуется тривиально. Делаешь (map expand ...) на параметры, а дальше работаешь с тем, что получилось. При большом желании можно сделать defsyntax* с встроенным map expand.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Ну сложность в том, что перед этим нужен pre-expand проход снаружи-вовнутрь, который трекнет биндинги. Ну и вообще любую статическую информацию можно тогда в это время трекать.

anonymous
()
Ответ на: комментарий от anonymous

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

anonymous
()
Ответ на: комментарий от monk

Надо #.(define x 2) вместо (define x 2), тогда должно работать, по идее.

anonymous
()
Ответ на: комментарий от anonymous

Ну то есть _текущий_ модуль в неймспейс добавить нельзя

Что и требовалось доказать...

В CL read-macro пользуются тем, что пространство имён общее и предыдущая top-level форма гарантированно загружена к моменту чтения следующей.

В Racket этого нет => все read-macro должны быть чистыми функциями.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Хотя, с другой стороны, а в REPL как работает?

monk ★★★★★
() автор топика
Ответ на: комментарий от anonymous

перед этим нужен pre-expand проход снаружи-вовнутрь, который трекнет биндинги.

А если (map expand-syntax args) — не протащит разве? В синтактических объектах.

monk ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.