I'm in a bigger code and I need to do it like:
file_1.rkt :
#lang racket
(provide define-type types-ref)
(require syntax/parse/define)
(begin-for-syntax
(define types (make-hasheq)))
(define-syntax-parser define-type
[(_ id type)
(hash-set! types (syntax->datum #'id) (syntax->datum #'type))
#'(void)])
(define-syntax-parser types-ref
[(_ id)
(writeln (hash-ref types (syntax->datum #'id)))
#'(void)])
file_2.rkt :
#lang racket
(provide (all-defined-out))
(require "file_1.rkt")
(define-type Atom Symbol)
(types-ref Atom)
out:
Symbol
file_3.rkt :
#lang racket
(require "file_1.rkt" "file_2.rkt")
(types-ref Atom)
out:
; hash-ref: no value found for key
; key: 'Atom
; Context (plain; to see better errortrace context, re-run with C-u prefix):
; /Applications/Racket v8.0/collects/syntax/parse/define.rkt:20:4
; /Applications/Racket v8.0/collects/syntax/wrap-modbeg.rkt:46:4
; /...
It seems that for each syntax expansion types is instantiated again.
I need to share the same types for different files. What can I do?
Do you really need to store the information in a hash table like that? A simpler way is to actually define id in define-type, so that you can properly provide it, and the other modules can properly require it.
It looks like you want define-type to occur at compile-time, so you can use define-syntax to create the binding, and use syntax-local-value to reference it.
#lang racket
(provide define-type types-ref)
(require syntax/parse/define)
(define-syntax-parser define-type
[(_ id type)
#'(define-syntax id (quote type))])
(define-syntax-parser types-ref
[(_ id)
(writeln (syntax-local-value #'id))
#'(void)])
Related
I'm trying to write the Scheme equivalent of this CL code:
(defmacro alias (new-name prev-name)
`(defmacro ,new-name (&rest args)
`(,',prev-name ,#args)))
;; Sample use:
(alias co concatenate)
My aim is to be able to use shorthand names for symbol and function names like:
(alias sa string-append)
(sa "ok" "not ok")
To do that I've tried this but it didn't work:
(define-syntax alias (new-name prev-name)
`(define-syntax ,new-name (#!rest args)
`(,',prev-name ,#args)))
Any help is appreciated. Thank you.
You can do this easily with a syntax-rules macro that defines another syntax-rules macro:
(define-syntax alias
(syntax-rules ()
((_ new-name prev-name)
(define-syntax new-name
(... (syntax-rules ()
((_ arg ...)
(prev-name arg ...))))))))
The trickiest thing is this macro is the use of ... to escape nested uses of ....
However, this is not necessarily the best way to do this. The best way probably depends on your precise Scheme implementation, as Scheme is less a language and more a family of languages. Writing portable Scheme is usually not very useful.
If your scheme supports R6RS syntax-case and cognates (say, guile or chez scheme), identifier-syntax is the most direct way of implementing what you want:
(define-syntax new-name (identifier-syntax old-name))
Thus:
(define-syntax new-display (identifier-syntax display))
(new-display "hello\n")
Edit: I see you are using chicken. In that case you can use er-macro-transformer to reproduce your defmacro solution (this works with chicken-4.10.0 at any rate):
(define-syntax alias
(er-macro-transformer
(lambda (exp r c)
(let ([new-name (cadr exp)]
[old-name (caddr exp)])
`(define-syntax ,new-name
(ir-macro-transformer
(lambda (exp i c)
`(,',old-name ,#(cdr exp)))))))))
By the way, in Common Lisp you can make an alias a real function, not a macro, by settings symbol-function of a symbol denoting an alias like this:
CL-USER> (defun foo (name)
(format nil "Hello ~A!~%" name))
FOO
CL-USER> (setf (symbol-function 'bar)
#'foo)
#<INTERPRETED-FUNCTION FOO>
CL-USER> (bar "Bob")
"Hello Bob!
"
Can I create a macro so that I can call sequence- functions with a s-? Hence, I should be able to write s-length, s-filter and s-map instead of sequence-length, sequence-filter and sequence-map. Thanks.
You can use filtered-in from racket/require to perform this sort of transformation. Here’s a simple example:
#lang racket
(require racket/require
(filtered-in (λ (name) (regexp-replace #rx"^sequence-" name "s-"))
racket/sequence))
(s-ref '(1 2 3) 1)
If you find yourself using this sort of thing often, it wouldn’t be too hard to write a require transformer that would expand to filtered-in:
#lang racket
(require (for-syntax racket/require-transform
syntax/parse)
racket/require)
(define-syntax reprefix-in
(make-require-transformer
(syntax-parser
[(_ original-prefix:id new-prefix:id require-spec:expr ...)
#:with replacer (string-append "^" (regexp-quote (symbol->string (syntax-e #'original-prefix))))
#:with replacement (symbol->string (syntax-e #'new-prefix))
(expand-import #'(filtered-in (λ (name) (regexp-replace (regexp 'replacer) name 'replacement))
(combine-in require-spec ...)))])))
Then you can use it like this:
(require (reprefix-in sequence- s- racket/sequence))
(s-ref '(1 2 3) 1)
Yes there is. To versing levels of cludgyness.
The way I highly recommend you do, however, is to use rename-in To rename each of these functions on import. So for example, your code would look like:
#lang racket
(require (rename-in racket/sequence
[sequence-length s-length]
[sequence-map s-map]
[sequence-filter s-filter]
...))
There are other more advanced ways to do this that do not require you to explicitly list out each identifier, using module->exports, regexp-match, format-id, and make-require-transformer. But this seems to brittle to me and you're better off being explicit about which names you want to rename.
(define bootstrap-c-code
(define (from-file file-name)
(let* ((ip (open-input-file file-name))
(res (read-text-file-from-input-port ip)))
(close-input-port ip)
res))
(from-file "llvm.c"))
Error : define: bad syntax (multiple expressions after identifier)
But I can't see anything wrong with it. Can someone explain / fix it please.
It's not clear what you intended with the above code. If you were trying to load a text file and leave the loaded value in a variable called bootstrap-c-code, then try this:
(define bootstrap-c-code
(let ((from-file
(lambda (file-name)
(let* ((ip (open-input-file file-name))
(res (read-text-file-from-input-port ip)))
(close-input-port ip)
res))))
(from-file "llvm.c")))
Of course, the from-file definition will only be visible inside the let, if you need to use it outside, define it outside of the whole expression. If you only need the functionality of from-file inside the let, you can obtain the same result in a much simpler way:
(define bootstrap-c-code
(let* ((ip (open-input-file "llvm.c"))
(res (read-text-file-from-input-port ip)))
(close-input-port ip)
res))
On the other hand, if what you intended was to create a procedure called bootstrap-c-code, then the correct syntax would be:
(define (bootstrap-c-code)
(define (from-file file-name)
(let* ((ip (open-input-file file-name))
(res (read-text-file-from-input-port ip)))
(close-input-port ip)
res))
(from-file "llvm.c"))
According to R5RS, internal definitions can occur only at the beginning of the of a bunch of forms like let, let*, lambda etc. In the case of your code, that is not the case since you have an internal definition inside a non-procedural define. You could fix it by making `bootstrap-c-code' bind to a procedure.
I have the following dumb test:
(define-syntax a
(lambda (stx)
(syntax-case stx ()
[(k e s) #'(let ((show display)) (e s))])))
(a show "something")
Why can't this work? (The error shows in DrRacket is expand: unbound identifier in module in: show.
However, The following can work:
(define-syntax a
(lambda (stx)
(syntax-case stx ()
[(k e s)
(with-syntax ((show (datum->syntax #'k 'show)))
#'(let ((show display)) (e s)))])))
(a show "something")
Then WHY?
Um, I assume that you're trying this out after reading the blog post I mentioned in an earlier answer -- but that blog post is explaining exactly this issue. Specifically, your first example has two different show identifiers, one that is bound by the macro, and a different one that is coming from the toplevel use (and is unbound). OTOH, in the second case you're creating a show with the lexical context of the user code.
In Exercise 35.4.2 from HtDP, I've implemented the GUI and have a button called "Remove" which invokes a callback function. Here it is:
(define (cb-remove x)
((lambda (name result)
(cond
[(number? result) (remove-name name address-book)]
[else (draw-message msg "Not found")]))
(string->symbol (text-contents label-name))
(lookup (string->symbol (text-contents label-name)) address-book)))
When I run this, I get the following message: button-callback: result of type <Boolean> expected, your function produced #<set!-result>. The problem is that I have to call set! in order to change the address book. However, the result of set! is (void), which cannot cannot be combined with a Boolean type. How can I avert this problem? Thanks for any insight.
Simple:
(begin (set! foo bar) #t)