The problem is quite difficult to explain because I need to collect my thoughts, so bear with me. I've been able to reduce the problem to a minimal example for illustrative purposes. The example will not make any sense as to what this would be useful for, but I digress. Say I want to extend the racket language to write things that look like this:
(define-something
(['a] 'whatever)
(['b 'c] 'whatever2))
Between the square brackets is a sequence of one or more symbols, followed by a sequence of racket expressions (the whatever's, which are not important for the problem statement)
The example would match a macro that looks something like this:
(define-syntax (define-something stx)
(syntax-case stx ()
[(_ ([symb ...] body ...) ...)
#'()]))
Actually here we match 0 or more symbols, but we can assume there is always going to be at least one.
In the macro's body I want to generate function definitions using the concatenated symbols as the identifier. So for our silly example the macro would expand to something like:
(define (a) 'whatever)
(define (bc) 'whatever2)
I have found a similar question where the poster generates functions using a pre-defined list of strings, but I am not that fluent with macro's so I have not been able to translate the concepts to solve my problem. I thought perhaps I could try generating a similar list (by concatenating the symbols) and applying their tactic, but I've been getting way too confused with all the ellipses in my macro definition. I'm also a bit confused about their use of an ellipsis in with-syntax.
It’s possible to solve this with with-syntax and syntax-case, but the easiest way to do this is by using syntax-parse’s syntax classes. By defining a syntax class that parses a list of symbols and produces a single concatenated identifier, you can lift the symbol parsing out of the macro body:
(require (for-syntax syntax/parse
racket/string))
(begin-for-syntax
(define-syntax-class sym-list
#:attributes [concatenated-id]
(pattern (~and stx (sym:id ...))
#:attr concatenated-id
(let* ([syms (syntax->datum #'(sym ...))]
[strs (map symbol->string syms)]
[str (string-append* strs)]
[sym (string->symbol str)])
(datum->syntax #'stx sym #'stx #'stx)))))
Now you can define your macro pretty easily:
(define-syntax (define-something stx)
(syntax-parse stx
[(_ (syms:sym-list body ...) ...)
#'(begin
(define (syms.concatenated-id) body ...)
...)]))
Note that this uses unquoted symbols in the name clause, so it would work like this:
(define-something
([a] 'whatever)
([b c] 'whatever2))
The names can’t be expressions that evaluate to symbols because the information needs to be known at compile-time to be available to macro expansion. Since you mentioned in a comment that this is for an FRP-like system, your signal graph will need to be static, like Elm’s is for example. If you want the ability to construct a dynamic signal graph, you’ll need a more complex strategy than macros since that information will need to be resolved at runtime.
Related
I'm trying to use syntax parameters in order to inject new syntax where I need it to be injected. The result of this is then used in other syntax.
However, it's not working as I expect it to. Here's a minimal working example:
(require racket/stxparam)
(require (for-syntax racket/stxparam))
;; declare parameter to be replaced with code
(define-syntax-parameter placeholder
(lambda (stx)
(raise-syntax-error
(syntax-e stx)
"can only be used inside declare-many-commands")))
;; this is just to print what 'arg' looks like
(define-syntax (print-syntax stx)
(syntax-case stx ()
[(_ arg)
#'(displayln 'arg)]))
;; this is the top-level entity invoked to produce many commands
(define-syntax-rule (declare-many-commands cmds)
(begin
(let ([X 10])
(syntax-parameterize
([placeholder (make-rename-transformer #'X)])
cmds))
(let ([X 20])
(syntax-parameterize
([placeholder (make-rename-transformer #'X)])
cmds))))
(declare-many-commands
(print-syntax placeholder))
What I would like to get as result when running this is:
10
20
but what I get is:
placeholder
placeholder
EDIT:
Posted a new question to refine the problem: Injecting syntax at compile time using Racket's syntax parameters?
The problem here is that your print-syntax macro quotes its input, and inputs to macro transformers are unexpanded syntax. This means that the expansion of (print-syntax placeholder) will always be (displayln 'placeholder), and no macroexpansion ever occurs under quote, so the placeholder binding in scope is irrelevant.
If you want to use the syntax parameter, you need to actually produce a reference to the placeholder binding. In this case, you just need to remove the use of quote. You could change print-syntax to (displayln arg), but at that point, there’s really no reason for print-syntax to be a macro, since it’s equivalent to the displayln function. Just use that instead:
(declare-many-commands
(displayln placeholder))
This will print 10 and 20 as you expect.
It’s possible you really do want the quote, and I don’t understand your question. In that case, though, I think it’s difficult for me to understand what you’re getting at without some additional context.
It's very common for Scheme macros to make "derived" identifiers, like how defining a record type foo (using the R6RS syntactic record API) will by default define a constructor called make-foo. I wanted to do something similar in my own macro, but I couldn't find any clean way within the standard libraries. I ended up writing this:
(define (identifier-add-prefix identifier prefix)
(datum->syntax identifier
(string->symbol (string-append prefix
(symbol->string (syntax->datum identifier)))))
I convert a syntax object (assumed to be an identifier) into a datum, convert that symbol into a string, make a new string with the prefix prepended, convert that string into a symbol, and then finally turn that symbol into an identifier in the same syntactic environment as identifier.
This works, but it seems roundabout and messy. Is there a cleaner or more idiomatic way to do this?
Although it might not be a hygienic macro, i suppose you could use define-syntax like this (in chicken scheme).
For chicken scheme the documentation for macros is here. Also this SO question sheds some light on chicken scheme macros. Finally i don't know if this would be an idiomatic way to approach the problem.
(use format)
(use srfi-13)
(define-syntax recgen
(lambda (expr inject compare)
`(define (,(string->symbol (string-append "make-" (cadr expr))) ) (format #t "called"))))
#> (recgen "bar")
#> (make-bar)
called
The single define above could be changed to a (begin ... ) that defines getters/setters or other ways to interact with the record.
Is there a way in Chicken Scheme to determine at run-time if a variable is currently defined?
(let ((var 1))
(print (is-defined? var)) ; #t
(print (is-defined? var)) ; #f
EDIT: XY problem.
I'm writing a macro that generates code. This generated code must call the macro in mutual recursion - having the macro simply call itself won't work. When the macro is recursively called, I need it to behave differently than when it is called initially. I would use a nested function, but uh....it's a macro.
Rough example:
(defmacro m (nested)
(if nested
BACKQUOTE(print "is nested")
BACKQUOTE(m #t)
(yes, I know scheme doesn't use defmacro, but I'm coming from Common Lisp. Also I can't seem to put backquotes in here without it all going to hell.)
I don't want the INITIAL call of the macro to take an extra argument that only has meaning when called recursively. I want it to know by some other means.
Can I get the generated code to call a macro that is nested within the first macro and doesn't exist at the call site, maybe? For example, generating code that calls (,other-macro) instead of (macro)?
But that shouldn't work, because a macro isn't a first-class object like a function is...
When you write recursive macros I get the impression that you have an macro expansion (m a b ...) that turns into a (m-helper a (b ...)) that might turn into (let (a ...) (m b ...)). That is not directly recursive since you are turning code into code that just happens to contain a macro.
With destructuring-bind you really only need to keep track of two variables. One for car and one for cdr and with an implicit renaming macro the stuff not coming from the form is renamed and thus hygenic:
(define-syntax destructuring-bind
(ir-macro-transformer
(lambda (form inject compare?)
(define (parse-structure structure expression optional? body)
;;actual magic happens here. Returns list structure with a mix of parts from structure as well as introduced variables and globals
)
(match form
[(structure expression) . body ]
`(let ((tmp ,expression))
,(parse-structure structure 'tmp #f body))))))
To check if something from input is the same symbol you use the supplied compare? procedure. eg. (compare? expression '&optional).
There's no way to do that in general, because Scheme is lexically scoped. It doesn't make much sense to ask if a variable is defined if an referencing an undefined variable is an error.
For toplevel/global variables, you can use the symbol-utils egg but it is probably not going to work as you expect, considering that global variables inside modules are also rewritten to be something else.
Perhaps if you can say what you're really trying to do, I can help you with an alternate solution.
I'm looking for the closest equivalent (both typographically and semantically) to what the following would do if functions in Elisp were "first-class":
(let ((f function-with-very-long-name))
(progn
...
(f ...) ;; evaluates to (function-with-very-long-name ...)
...
)
)
IOW, I'm looking for a convenient way to define lexically scoped aliases for functions.
The closest I've found involves binding the aliasing symbol (f in the example above) to a lambda that in turn calls the aliased function. I find this approach typographically cumbersome. (It negates whatever typographic simplification the rest of the code may have gained from the aliasing.)
Is there anything better?
I think the simplest way is to use cl-flet or cl-labels (the exact names may depend on which version of Emacs you are using, due to the great cl-* renaming. You can also use cl-letf with (symbol-function 'symbol) if you prefer, though I think that's needlessly obscure.
You can use funcall for this. For example, the let below passes 21 to a-function-with-an-extremely-long-name, which doubles it and returns 42:
(defun a-function-with-an-extremely-long-name (i) (* 2 i))
(let ((f 'a-function-with-an-extremely-long-name))
(funcall f 21))
The Typed Racket reference indicates that it's possible to use with-type to created “typed regions” within untyped code.
The with-type form allows for localized Typed Racket regions in otherwise untyped code.
It’s a little unclear how to actually use this, though. Obviously, using such a feature needs to take place within an untyped module using #lang racket or something similar. How should the with-type binding be imported?
A naïve attempt is just to require Typed Racket, but this causes failures with how TR overwrites existing syntactic forms.
(require typed/racket)
(struct point (x y)) ; complains about missing type annotations
Trying to use only-in to simply require with-type and nothing else sort of works, but then none of the required type bindings (such as Number or ->) exist.
It seems like the only way to do this would be to manually use only-in to import only the things that I need, but this feels laborious. I could also use prefix-in, but then of course everything would be scattered with prefixes.
Is there a recommended way of doing this, or is this feature somewhat deprecated?
I don't know the fundamental answer. A guess is that it's the sort of thing that would be useful when writing macros, as opposed to code you'd write directly?
A practical idea: You can use local-require to limit the "contamination" of the TR require. And you can flip to using except-in if that's less work then only-in.
For instance this example from the docs get close, but gives a weird error presumably because it's using TR's quote:
#lang racket/base
(let ([x 'hello])
(local-require typed/racket)
(with-type
#:result String
#:freevars ([x String])
(string-append x ", world")))
; /tmp/so.rkt:7:21: quote: identifier used out of context
; in: quote
Excluding that with except-in gives the desired error:
(let ([x 'hello])
(local-require (except-in typed/racket quote))
(with-type
#:result String
#:freevars ([x String])
(string-append x ", world")))
; x: broke its contract
; promised: String
; produced: 'hello
; in: String
; contract from: /tmp/so.rkt
; blaming: /tmp/so.rkt
; (assuming the contract is correct)
; at: /tmp/so.rkt:14.17
But yeah. This is just fiddling with the edges and not getting to the heart of it.
I would just use except-in (or perhaps rename-in) to avoid the few identifiers that don't work in both typed and untyped programs. Like this modification of Greg's program:
#lang racket/base
(require (except-in typed/racket struct))
(struct point (x y))
(let ([x 'hello])
(with-type
#:result String
#:freevars ([x String])
(string-append x ", world")))