How to find out if racket is defined or not

How can you have different behavior if the variable is defined or not in the racket language?

+6
source share
2 answers

There are several ways to do this. But I suspect that none of them is what you want, so I will give pointers to functions (and explain the problems with each of them):

  • namespace-variable-value is a function that extracts the value of a top-level variable from some namespace. This is only useful when interacting with REPL and REPL code, because the code defined in the module will not use these things in any case. In other words, you can use this function (and the corresponding namespace-set-variable-value! ) To get the values โ€‹โ€‹(if any) and set them, but the only use of these values โ€‹โ€‹is in code that is not a module itself. In other words, using this tool is no worse than saving a hash table that maps characters to values, only a little more convenient in REPL, because you just type names ...

  • Most likely, such things are done in macros. The first way to do this is to use the special macro #%top . This macro is automatically inserted for all names in a module that are not known to be associated. The usual thing this macro does is throw an error, but you can override it in your code (or create your own language that overrides it), which does something else with these unknown names.

  • A slightly more complicated way to do this is to use the identifier-binding function - again, in the macro, and not at run time - and use it to get information about some name that is provided to the macro, and decide what should be expanded based on that name.

The last two options are more useful, but they are not beginner level macros, so I suspect you are asking the wrong question. To clarify, can you use them to write a kind of special form defined? which checks if some name is defined, but this question is the one the macro will answer based on the rest of the code, so itโ€™s not really useful to ask about it. If you want something like this that can include the look of code in other dynamic languages โ€‹โ€‹where you use such a predicate, then the best way to do this is to override #%top to do some sort of searching (hash table or global namespace) instead of throwing a compilation error - but again, the difference between this and using a hash table is clearly mostly cosmetic (and again, this is not a newbie).

+9
source

Read Eli's answer first. Then, based on Eli's answer, can you implement a defined? macro defined? in the following way:

 #lang racket ; The macro (define-syntax (defined? stx) (syntax-case stx () [(_ id) (with-syntax ([v (identifier-binding #'id)]) #''v)])) ; Tests (define x 3) (if (defined? x) 'defined 'not-defined) ; -> defined (let ([y 4]) (if (defined? y) 'defined 'not-defined)) ; -> defined (if (defined? z) 'defined 'not-defined) ; -> not-defined 

It works for this main case, but it has a problem: if z is undefined, the if branch, which believes that it is defined and uses its value, will cause a compile-time error, because normal if checks its condition value at runtime (dynamically ):

 ; This doesn't work because z in `(list z)' is undefined: (if (defined? z) (list z) 'not-defined) 

So what you probably want is an if-defined macro that tells you at compile time (and not at run time) which if branch to take:

 #lang racket ; The macro (define-syntax (if-defined stx) (syntax-case stx () [(_ id iftrue iffalse) (let ([where (identifier-binding #'id)]) (if where #'iftrue #'iffalse))])) ; Tests (if-defined z (list z) 'not-defined) ; -> not-defined (if-defined t (void) (define t 5)) t ; -> 5 (define x 3) (if-defined x (void) (define x 6)) x ; -> 3 
+5
source

Source: https://habr.com/ru/post/958409/


All Articles