Define a subset of Racket [closed] - lisp

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
Since Racket is well-known for his ability to create new programming language, the following shouldn't be too difficult.
I would like to create a subset of Racket (let's name it min) for an educational purpose renaming some function (tail instead of cdr) and ignoring others (such as string=? and = to just have equal?).
The first step I made is to start my min files with #lang s-exp "min.rkt" but I am stuck at the expander stage.

The following module is an example of a minimal subset of Racket that allows top-level definitions, constants, and arithmetic using + and *:
;; min.rkt
#lang racket/base
(provide #%module-begin #%top-interaction
#%app #%datum #%top
define + *)
Here's what the provides mean:
#%module-begin must be provided by a module for that module to be considered a "language"; it determines what a module body means. You can just reuse Racket's module-begin macro. (The #%module-begin export gives you a hook to implement non-local constraints or transformations. For example, if you wanted to add a typechecker or check that variables are defined in alphabetical order, you could do that in the module-begin hook.)
#%top-level is necessary for interactive languages. If you leave it out, you can't use a REPL for your language (eg, with racket -t "min.rkt" -i).
#%app and #%datum make function application and self-evaluating constants (like numbers and booleans) work.
#%top makes forward references work at the REPL, like in mutually-recursive functions. You still must define a name before you evaluate a reference to it, of course.
The rest of the exports are the special forms and functions you want to include in your language.
Here's a program in this "min.rkt" language:
#lang s-exp "min.rkt"
(define x 2)
(define y (+ x 5))
(* y 7)
(define (f x) (+ x x 1))
(f 8)
Note that since the language includes Racket's define, it allows function definition, even though the language doesn't include lambda. If you wanted a restricted version of define, you would have to define your own macro and provide it as your language's define, like (provide (rename-out [my-define define])).
You can also use rename-out to provide Racket's cdr as tail, but the procedure would still print as #<procedure:cdr> and if it raised an error the error message would still say cdr. To change that, you'd need to define your own wrapper function that does its own error checking.

Related

detecting dialect in Racket

I would like to write code that is correct for both untyped Racket and typed/racket...
For now, I've come up with the following not-so-satisfying principle: I insert a dummy syntax definition for ':' at the beginning of the file, so that the annotations are skipped when using untyped racket. And I comment this definition when using typed/racket.
E.g:
#lang racket
; comment the following line for typed/racket
(define-syntax : (syntax-rules () ((_ id type) (void))))
(: fact (-> Integer Integer))
; the rest of the file is common to both racket and typed/racket
(define (fact n) (if (zero? n) 1 (* n (fact (sub1 n)))))
and
#lang typed/racket
; comment the following line for typed/racket
;(define-syntax : (syntax-rules () ((_ id type) (void))))
(: fact (-> Integer Integer))
; the rest of the file is common to both racket and typed/racket
(define (fact n) (if (zero? n) 1 (* n (fact (sub1 n)))))
This way I just need to remove/insert a ';' to switch between racket and typed/racket...
But is there a way to have a code that doesn't need any change to run in racket and typed/racket? I didn't find how to programmatically detect if I'm in racket or typed/racket... Then I guess I would also have to find a way to conditionally define ':' at the top-level... All this doesn't seem the way to go, so, is there a better way ?
Generally, if you want code to work with both #lang racket and #lang typed/racket, just write your code in #lang typed/racket. When you require a module written in #lang typed/racket from a module written in #lang racket, contracts will automatically be inserted between the two modules to enforce the types. You don’t have to do anything special to require a typed module from an untyped one, so from the user’s perspective, they don’t have to care.
The one area where you might need to worry about being in a typed or untyped context is when writing macros. Often, you can expand to the same code in both situations, but sometimes, you have to do things differently depending on whether or not the target code is typed. For that, you can use define-typed/untyped-identifier, which allows specifying two different forms to be used in different contexts.
If you really need to detect whether or not the current expansion context is typed, you can use the large hammer syntax-local-typed-context?. However, the documentation itself recommends avoiding its use:
This is the nuclear option, provided because it is sometimes, but rarely, useful. Avoid.

Scheme apply a macro to given S-Expression

I have some s-expression (let ((whatever (foo (bar 4) (bar 5)))) ...) (as a result of (read "(whatever (foo (bar 4) (bar 5)))"). Now I would like to transform it with a custom macro that expands for example foo into the macro expression.
What is the mechanism to apply macros to given S-Expressions? Note that I do not want this substitution to happen at compiletime of the .scm file but but after reading in the s expression.
Furthermore, I don't want to use eval, since these S-Expressions are not Scheme code.
I would not want to expand a let statement in that given s-expression, only foo.
Basically I thought that Scheme would contain a sufficiently flexible Tree-Transformation Framework that would enable me to use specific macros for manipulating any kind of S-expressions at any time. In the meantime however, I learned that Scheme's macros are not first class objects and cannot be used this way, as also implied by Sylwester.
I presume you want to expand data and end up with data. If that is not the case, please update your question with more information.
You'll need to run your own macro-implementation. Let's say you create macros with make-macro and expand them with expand-macros such that only expands you user defined macros.
Then the solution would be:
(let ((whatever (expand-macros (read))))
...)
There are lots of macro-implementation you can look at. Alexpander is one based on on hygienic syntax-rules while a classical unygenic defmacro + expander would be very easy. However, it would impossible to make if completely safe. Imagine your foo:
(let ((foo +))
(foo 5 6))
This should override you definition of foo with + in the let. To fix this your expander needs to know all language constructs of Scheme that you are going to use and be able to understand that it's bindings can become shadowed. All in all you'll almost need it to be an interpreter for Scheme to be able to see what to expand or not. It's not so easy, but it's doable.

Why the function/macro dichotomy?

Why is the function/macro dichotomy present in Common Lisp?
What are the logical problems in allowing the same name representing both a macro (taking precedence when found in function position in compile/eval) and a function (usable for example with mapcar)?
For example having second defined both as a macro and as a function would allow to use
(setf (second x) 42)
and
(mapcar #'second L)
without having to create any setf trickery.
Of course it's clear that macros can do more than functions and so the analogy cannot be complete (and I don't think of course that every macro shold also be a function) but why forbidding it by making both sharing a single namespace when it could be potentially useful?
I hope I'm not offending anyone, but I don't really find a "Why doing that?" response really pertinent... I'm looking for why this is a bad idea. Imposing an arbitrary limitation because no good use is known is IMO somewhat arrogant (sort of assumes perfect foresight).
Or are there practical problems in allowing it?
Macros and Functions are two very different things:
macros are using source (!!!) code and are generating new source (!!!) code
functions are parameterized blocks of code.
Now we can look at this from several angles, for example:
a) how do we design a language where functions and macros are clearly identifiable and are looking different in our source code, so we (the human) can easily see what is what?
or
b) how do we blend macros and functions in a way that the result is most useful and has the most useful rules controlling its behavior? For the user it should not make a difference to use a macro or a function.
We really need to convince ourselves that b) is the way to go and we would like to use a language where macros and functions usage looks the same and is working according to similar principles. Take ships and cars. They look different, their use case is mostly different, they transport people - should we now make sure that the traffic rules for them are mostly identical, should we make them different or should we design the rules for their special usage?
For functions we have problems like: defining a function, scope of functions, life-time of functions, passing functions around, returning functions, calling functions, shadowing of functions, extension of functions, removing the definition a function, compilation and interpretation of functions, ...
If we would make macros appear mostly similar to functions, we need to address most or all above issues for them.
In your example you mention a SETF form. SETF is a macro that analyses the enclosed form at macro expansion time and generates code for a setter. It has little to do with SECOND being a macro or not. Having SECOND being a macro would not help at all in this situation.
So, what is a problem example?
(defmacro foo (a b)
(if (and (numberp b) (zerop b))
a
`(- ,a ,b)))
(defun bar (x list)
(mapcar #'foo (list x x x x) '(1 2 3 4)))
Now what should that do? Intuitively it looks easy: map FOO over the lists. But it isn't. When Common Lisp was designed, I would guess, it was not clear what that should do and how it should work. If FOO is a function, then it was clear: Common Lisp took the ideas from Scheme behind lexically scoped first-class functions and integrated it into the language.
But first-class macros? After the design of Common Lisp a bunch of research went into this problem and investigated it. But at the time of Common Lisp's design, there was no wide-spread use of first-class macros and no experience with design approaches. Common Lisp is standardizing on what was known at the time and what the language users thought necessary to develop (the object-system CLOS is kind of novel, based on earlier experience with similar object-systems) software with. Common Lisp was not designed to have the theoretically most pleasing Lisp dialect - it was designed to have a powerful Lisp which allows the efficient implementation of software.
We could work around this and say, passing macros is not possible. The developer would have to provide a function under the same name, which we pass around.
But then (funcall #'foo 1 2) and (foo 1 2) would invoke different machineries? In the first case the function fooand in the second case we use the macro foo to generate code for us? Really? Do we (as human programmers) want this? I think not - it looks like it makes programming much more complicated.
From a pragmatic point of view: Macros and the mechanism behind it are already complicated enough that most programmers have difficulties dealing with it in real code. They make debugging and code understanding much harder for a human. On the surface a macro makes code easier to read, but the price is the need to understand the code expansion process and result.
Finding a way to further integrate macros into the language design is not an easy task.
readscheme.org has some pointers to Macro-related research wrt. Scheme: Macros
What about Common Lisp
Common Lisp provides functions which can be first-class (stored, passed around, ...) and lexically scoped naming for them (DEFUN, FLET, LABELS, FUNCTION, LAMBDA).
Common Lisp provides global macros (DEFMACRO) and local macros (MACROLET).
Common Lisp provides global compiler macros (DEFINE-COMPILER-MACRO).
With compiler macros it is possible to have a function or macro for a symbol AND a compiler macro. The Lisp system can decide to prefer the compiler macro over the macro or function. It can also ignore them entirely. This mechanism is mostly used for the user to program specific optimizations. Thus it does not solve any macro related problems, but provides a pragmatic way to program global optimizations.
I think that Common Lisp's two namespaces (functions and values), rather than three (macros, functions, and values), is a historical contingency.
Early Lisps (in the 1960s) represented functions and values in different ways: values as bindings on the runtime stack, and functions as properties attached to symbols in the symbol table. This difference in implementation led to the specification of two namespaces when Common Lisp was standardized in the 1980s. See Richard Gabriel's paper Technical Issues of Separation in Function Cells and Value Cells for an explanation of this decision.
Macros (and their ancestors, FEXPRs, functions which do not evaluate their arguments) were stored in many Lisp implementations in the symbol table, in the same way as functions. It would have been inconvenient for these implementations if a third namespace (for macros) had been specified, and would have caused backwards-compatibility problems for many programs.
See Kent Pitman's paper Special Forms in Lisp for more about the history of FEXPRs, macros and other special forms.
(Note: Kent Pitman's website is not working for me, so I've linked to the papers via archive.org.)
Because then the exact same name would represent two different objects, depending on the context. It makes the programme unnecessarily difficult to understand.
My TXR Lisp dialect allows a symbol to be simultaneously a macro and function. Moreover, certain special operators are also backed by functions.
I put a bit of thought into the design, and haven't run into any problems. It works very well and is conceptually clean.
Common Lisp is the way it is for historic reasons.
Here is a brief rundown of the system:
When a global macro is defined for symbol X with defmacro, the symbol X does not become fboundp. Rather, what becomes fboundp is the compound function name (macro X).
The name (macro X) is then known to symbol-function, trace and in other situations. (symbol-function '(macro X)) retrieves the two-argument expander function which takes the form and an environment.
It's possible to write a macro using (defun (macro X) (form env) ...).
There are no compiler macros; regular macros do the job of compiler macros.
A regular macro can return the unexpanded form to indicate that it's declining to expand. If a lexical macrolet declines to expand, the opportunity goes to a more lexically outer macrolet, and so on up to the global defmacro. If the global defmacro declines to expand, the form is considered expanded, and thus is necessarily either a function call or special form.
If we have both a function and macro called X, we can call the function definition using (call (fun X) ...) or (call 'X ...), or else using the Lisp-1-style dwim evaluator (dwim X ...) that is almost always used through its [] syntactic sugar as [X ...].
For a sort of completeness, the functions mboundp, mmakunbound and symbol-macro are provided, which are macro analogs of fboundp, fmakunbound and symbol-function.
The special operators or, and, if and some others have function definitions also, so that code like [mapcar or '(nil 2 t) '(1 0 3)] -> (1 2 t) is possible.
Example: apply constant folding to sqrt:
1> (sqrt 4.0)
2.0
2> (defmacro sqrt (x :env e :form f)
(if (constantp x e)
(sqrt x)
f))
** warning: (expr-2:1) defmacro: defining sqrt, which is also a built-in defun
sqrt
3> (sqrt 4.0)
2.0
4> (macroexpand '(sqrt 4.0))
2.0
5> (macroexpand '(sqrt x))
(sqrt x)
However, no, (set (second x) 42) is not implemented via a macro definition for second. That would not work very well. The main reason is that it would be too much of a burden. The programmer may want to have, for a given function, a macro definition which has nothing to do with implementing assignment semantics!
Moreover, if (second x) implements place semantics, what happens when it is not embedded in an assignment operation, such that the semantics is not required at all? Basically, to hit all the requirements would require concocting a scheme for writing macros whose complexity would equal or exceed that of existing logic for handling places.
TXR Lisp does, in fact, feature a special kind of macro called a "place macro". A form is only recognized as a place macro invocation when it is used as a place. However, place macros do not implement place semantics themselves; they just do a straightforward rewrite. Place macros must expand down to a form that is recognized as a place.
Example: specify that (foo x), when used as a place, behaves as (car x):
1> (define-place-macro foo (x) ^(car ,x))
foo
2> (macroexpand '(foo a)) ;; not a macro!
(foo a)
3> (macroexpand '(set (foo a) 42)) ;; just a place macro
(sys:rplaca a 42)
If foo expanded to something which is not a place, things would fail:
4> (define-place-macro foo (x) ^(bar ,x))
foo
5> (macroexpand '(foo a))
(foo a)
6> (macroexpand '(set (foo a) 42))
** (bar a) is not an assignable place

Arbitrary computation in Scheme macro

Scheme macros, at least the syntax-case variety, are said to allow arbitrary computation on the code to be transformed. However (both in the general case and in the specific case I'm currently looking at) this requires the computation to be specified in terms of recursive functions. When I try various variants of this, I get e.g.
main.scm:32:71: compile: unbound identifier in module (in the transformer environment, which does not include the run-time definition) in: expand-vars
(The implementation is Racket, if it matters.)
The upshot seems to be that you can't define named functions until after macro processing.
I suppose I could resort to the Y combinator, but I figure it's worth asking first whether there's a better approach?
Yes, the fact that you're using Racket matters -- in Racket, there is something that is called "phase separation", which means that the syntax level cannot use runtime functions. For example, this:
#lang racket
(define (bleh) #'123)
(define-syntax (foo stx)
(bleh))
(foo)
will not work since bleh is bound at a runtime, not available for syntax. Instead, it should be
(define-for-syntax (bleh) #'123)
or
(begin-for-syntax (define (bleh) #'123))
or moved as an internal definition to the macro body, or moved to its own module and required using (require (for-syntax "bleh.rkt")).

What are some things that you've used Scheme macros for? [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
Many examples of macros seem to be about hiding lambdas, e.g. with-open-file in CL. I'm looking for some more exotic uses of macros, particularly in PLT Scheme. I'd like to get a feel for when to consider using a macro vs. using functions.
Macros are needed in order to implement new control structures and new binding constructs.
Thus look for these kinds of constructs at http://planet.plt-scheme.org.
At PLaneT you both browse the documentation and the code.
Examples for new control structures:
http://planet.plt-scheme.org/package-source/soegaard/control.plt/2/0/planet-docs/manual/index.html
To find examples of new binding forms, look for macros that begin with "with-".
One useful example is found in math.plt also from PLaneT.
; Within a (with-modulus n form1 ...) the return values of
; the arithmetival operations +, -, * and ^ are automatically
; reduced modulo n. Furthermore (mod x)=(modulo x n) and
; (inv x)=(inverse x n).
; Example: (with-modulus 3 (^ 2 4)) ==> 1
(define-syntax (with-modulus stx)
(syntax-case stx ()
[(with-modulus e form ...)
(with-syntax ([+ (datum->syntax-object (syntax with-modulus) '+)]
[- (datum->syntax-object (syntax with-modulus) '-)]
[* (datum->syntax-object (syntax with-modulus) '*)]
[^ (datum->syntax-object (syntax with-modulus) '^)]
[mod (datum->syntax-object (syntax with-modulus) 'mod)]
[inv (datum->syntax-object (syntax with-modulus) 'inv)])
(syntax (let* ([n e]
[mod (lambda (x) (modulo x n))]
[inv (lambda (x) (inverse x n))]
[+ (compose mod +)]
[- (compose mod -)]
[* (compose mod *)]
[square (lambda (x) (* x x))]
[^ (rec ^ (lambda (a b)
(cond
[(= b 0) 1]
[(even? b) (square (^ a (/ b 2)))]
[else (* a (^ a (sub1 b)))])))])
form ...)))]))
I only use Scheme macros (define-syntax) for tiny things like better lambda syntax:
(define-syntax [: x]
(syntax-case x ()
([src-: e es ...]
(syntax-case (datum->syntax-object #'src-: '_) ()
(_ #'(lambda (_) (e es ...)))))))
Which lets you write
[: / _ 2] ; <-- much better than (lambda (x) (/ x 2))
Dan Friedman has a mind-bending implementation of OO using macros: http://www.cs.indiana.edu/~dfried/ooo.pdf
But honestly, all the useful macros I've defined are stolen from Paul Graham's On Lisp and are generally easier to write with defmacro (define-macro in PLT Scheme). For example, aif is pretty ugly with define-syntax.
(define-syntax (aif x)
(syntax-case x ()
[(src-aif test then else)
(syntax-case (datum->syntax-object (syntax src-aif) '_) ()
[_ (syntax (let ([_ test]) (if (and _ (not (null? _))) then else)))])]))
define-syntax is odd in that it's only easy to use for very simple macros, where you are glad of the inability to capture variables; and very complicated macro DSLs, where you are glad of the inability to capture variables easily. In the first case you want to write the code without thinking about it, and in the second case you have thought enough about the DSL that you are willing to write part of it in the syntax-rules/syntax-case language which is not Scheme in order to avoid mystifying bugs.
But I don't use macros that much in Scheme. Idiomatic Scheme is so functional that many times you just want to write a functional program and then hide a few lambdas. I got on the functional train and now believe that if you have a lazy language or a good syntax for lambda, even that isn't necessary, so macros are not all that useful in a purely functional style.
So I'd recommend Practical Common Lisp and On Lisp. If you want to use PLT Scheme, I think most of their defmacro macros will work with define-macro. Or just use Common Lisp.
I'll start answering the last question. When to use a macro instead of a function. The macros do things the functions can't, and the functions do thing the macros can't, so it'll be hard to mix them, but let's go deeper.
You use functions when you want the arguments evaluated and macros when you want the arguments un-evaluated. That's not very useful, is it? You use macros when you want to write something in a different way, when you see a pattern and you want to abstract. For example: I define three functions called foo-create, foo-process and foo-destroy for different values of foo and with similar bodies where the only change is foo. There's a pattern but a too-high level for a function, so you create a macro.
In my humble experience, macros in Scheme are to used as much as in other Lisps, like Common Lisp or Clojure. I suppose it's proof that maybe hygienic macros are not such a good idea, and here I would disagree with Paul Graham about why. It's not because sometimes you want to be dirty (un-hygienic) but because hygienic macros end up being complex or convoluted.
Practical Common Lisp, by Peter Seibel, has a good introduction to macros. On Lisp, by Paul Graham, might be a good source of more complicated examples. Also, have look at the built-in macros in, say, Common Lisp.
The Automata via Macros paper presents a functional programming pearl on implementing finite state machines via macros in Scheme.
The book The Reasoned Schemer ends with a full macro-based implementation of miniKanren, the logic programming language used in the book. This paper presents miniKanren and its implementation more formally and concisely than in the book.
An example of a more advanced macro that is not a lambda form in disguise is Common Lisp's macro with-slots, which makes object slot access look like ordinary variable access:
(with-slots (state door) car
(when (eq state :stopped)
(setq state :driving-around)
(setq door :closed)))
Note that this is not the same as binding the slot values to local variables and accessing those, as with-slots allows you to alter slots by way of SETQ and see external changes immediately.
I had a curry macro when I used to do a lot of scheme on my palm. It was pretty handy.
Scheme macros let you add features that the original language authors did not include themselves; that is the whole philosophy behind macros.
Here is a tiny example: PLT Scheme provides a language for writing presentations called Slideshow. I used macros to associate a slide number with a slide so that I could more easily manage them.
I’ve written a macro that provides infix syntax. Nothing too fancy; no precedence. While I’m generally fine with prefix syntax, I prefer infix for < and >.
I use them when procedures do not suffice.