Closed GrinDeg closed 4 years ago
Thanks for letting me know. I can confirm it displays nothing for me, using the program in the link you supplied: https://docs.racket-lang.org/lindenmayer/Interpreting_L-systems.html
#lang lindenmayer racket
## axiom ##
X
## rules ##
X -> F[+X]F[-X]+X
F -> FF
## variables ##
n=7
θ=20
=============================================
(require lindenmayer/turtle)
(provide (all-from-out lindenmayer/turtle) X)
(define (X turtles variables) turtles)
Basically the image support today relies on Racket programs printing values that support file/convertible. Racket Mode's Racket back end print-handler can intercept these and create a PNG file for the Emacs Lisp front end to display.
I'll have to look at this in more depth to understand whether lindenmayer prints such file/convertible
values (or not), and as a result whether this is a bug to fix or an enhancement to make, and either way what work would need to happen.
For now I'll assume it's a bug and tag it that way.
Take this little program, simple.rkt
:
#lang slideshow
(circle 10)
And run it using command-line racket
:
$ racket simple.rkt
#<pict>
You see #<pict>
because "the #%module-begin
form of racket/base
wraps every top-level expression to print non-#<void>
results using current-print
.")) . The printed representation of (circle 10)
is a pict?
struct
, which is opaque and therefore prints as #<pict>
.
Racket Mode's back end installs a print-handler. If it sees a value that is convertible?
, it tries to convert it to png-bytes
, saves that to a temp .png file, and prints something like #<Image: /path/to/temp-file.png>
. Then the front end Emacs code can spot such values, and replace them in the buffer with a display of the image.
If you take that Lindenmayer example program:
$ racket lindenmayer-example.rkt
It prints... nothing.
So I think the issue here is that lindenmayer/turtles
programs don't evaluate to values at the module level? And/or it uses a #%module-begin
that does not print?
The documentation for finish
says that it returns a pict?
. That would be convertible?
, if Racket Mode could see it, but it doesn't. Maybe instead it assumes you're running in Dr Racket and draws directly to a dc??
That's my research so far. It's not yet clear to me if this is a bug in Racket Mode that I would be able to fix, or, a design design in lindenmayer/turtles
.
Note: This technique of displaying images is something I originally learned from Geiser. Assuming I can fix this, in Racket Mode, I'll submit/suggest a similar fix, for Geiser.
OK, it turns out this has nothing to do with how the image is printed. Instead, it's about when it's printed.
lindenmayer/turtle
defines a main
submodule. It prints the image when the main
submodule is evaluated -- not the module for the .rkt
file.
Running the main
submodule happens automatically in Dr Racket.
Instead, Racket Mode lets you run any submodule -- just put point inside it. (It doesn't automatically run main
because maybe main
has startup code, the rest of the file has support code, and you don't want main
to run if you're working on the latter. You choose.)
The catch here is linenmayer/turtle
defines the main
submodule, not your program. So in the example program, there's no main
submodule to put point in. :smile:
As a work-around: Add (module+ main (void)
at the end of the example program. Due to how module+
works, this extends the main
submodule; it's not an error.
#lang lindenmayer racket
## axiom ##
X
## rules ##
X -> F[+X]F[-X]+X
F -> FF
## variables ##
n=7
θ=20
=============================================
(require lindenmayer/turtle)
(provide (all-from-out lindenmayer/turtle) X)
(define (X turtles variables) turtles)
(module+ main
(void))
Put point anywhere inside that (module+ main (void))
form, then M-x racket-run
or C-c C-c. Now the image will print.
I think this answers your original question, which had a question
label on it. And I'm not sure if my bug
label makes sense. However I'm not going to close this, yet. I'd like to think about what if anything could/should change to make this less surprising. I'm not a fan of always running main
-- maybe not even a user option to always run it. But I'll think.
This solution might be an issue for languages like https://github.com/florence/pop-pl, which
use the main
and test
submodules but don't provide a syntactic hook to them.
Maybe racket-mode could have a (user extensible) table somewhere that says "when in these languages, please always run these submodules"?
Maybe racket-mode could have a (user extensible) table somewhere that says "when in these languages, please always run these submodules"?
I'm OK adding such a thing as a work-around. I think the precise meaning would be, "When point is in the file module (not any submodule) instead of running that as usual, run the XXX submodule(s)".
Also, if it were an Emacs variable like racket-submodule-to-run-instead-of-file-module
, you could add that to the .rkt
file in a comment as a file-local variable value (or in .dir-locals.el
once for all files in a dir).
Having said all that, this feels a bit weird.
Someone new to Lindenmayer and/or Racket, still won't get the expected result until they add this configuration. It won't "just work".
Usually it does "just work" because most Racket languages let #%module-begin
print module-level expressions and let user programs have such values. Doing so works well with all tools: Plain command-line racket
, xrepl
's ,enter
command (which, again, behaves like Racket Mode for this issue), Dr Racket, Racket Mode.
To me, the main
submodule in a user's program is something for the user -- not a library or language. It is where users can put things like configuration or side-effecting interactions like reset-the-database!
. If a library provides such things, the user's main
submodule is where they get to choose how/when/if to call them.
Similarly a lib/lang should have test
submodules, but should it create ones that mix with the user's test
submodules? That's like saying srcdoc
submodules should mix, and the use of a lang/lib should get some of its documentation mixed in. (Which, idk, maybe there's a clever case for that, like libs forcibly injecting their copyright notices into using apps/libs, but I don't think it's the normal unsurprising case?)
I don't mean this to sound like a long rant; I'm really just typing things out in an effort to articulate why this feels weird to me. I freely admit that doesn't mean I'm right about that. :smile:
If you're reading my previous comment in email, I just made few minor edits that AFAIK GitHub won't email to you.
I think you are right about the rationale for putting things into a main submodule and the lindenmayer language is hewing closer to that rationale than maybe it seems. In particular, the things in the main submodule are thigns that actually run the lindenmayer system and if you require the file you get access to the lindenmayer system as a library function.
On a related point, I don't think that the way DrRacket chooses which submodules to run is optimal (from the UI pov). It does, by default, however run the main module when you click "Run" (as "Run" is supposed to mean "Run the program", i.e., do something roughly inspired by what racket x.rkt
does and not what (require "x.rkt")
does).
(I would be happier if DrRacket and Racket Mode worked more similarly along these lines and am happy to (try to ... based on others' feedback) change DrRacket.)
Thanks for the feedback.
I'm also open to changing things, including giving Racket Mode users choices and guidance how to make things work more similarly to Dr Racket (or less, as they prefer).
As a tiny example, already there is a racket-run
command, which keeps the edit buffer selected -- and also a racket-run-and-switch-to-repl
command. I prefer the former but the latter is closer to Dr Racket -- Racket Mode even binds it to F5 by default. :smile:
I could see renaming racket-run
to racket-enter-submodule-at-point
. And then, a new racket-run
actually means "run 'the program'" i.e. main
submodule if it exists else the file module. (But I could also see making C-c C-c bound to the latter, so that the status quo doesn't change for existing Racket Mode users.)
I could also see adding a short section to Configure that discusses the various bindings and variables you can change to make Racket Mode behave more like Dr Racket.
Adding a "enter submodule at cursor" command to Dr Racket would be nice, IMHO. I find it extremely handy in Racket Mode. Run main
, tests
, slow-tests
, example
, or whatever submodules make sense.
It might be harder for Dr Racket to implement for unsaved editors. (Racket Mode auto-saves the file, first.) Maybe just... name the command "save file and enter submodule at cursor". :smile: I'm only partly joking.
I would like to see the "run the program and be inside the module at the point" functionality in DrRacket. How does racket mode achieve that? Does it explicitly expand the program and look for submodules as part of the process of running a program? (DrRacket doesn't explicitly get hold of the fully expanded program during running).
It just looks for module
/module*
/module+
forms in the source, textually, walking up from point (cursor), reverses the list, and gives the module path to module->namespace
.
Yes, textually. OTOH as an alternative to supplying such text in some UI, and as (> something nothing)
, I think it's been fine so far. Admittedly does not work in non-sexpr langs or those that rename module
.
(And so, if drracket/check-syntax
were to return annotations about modules, that would be a better way for this to work, someday.)
@GrinDeg If you're feeling spammed by this issue discussion being so long, for your simple question, I apologize. Remember you can click its Unsubscribe
button in the GitHub web site UI! :smile:
re "It just looks for module/module*/module+ forms in the source, textually ...": oh. I'm not excited to add that to DrRacket. As for check syntax reporting something about a mapping from source locations to submodules, that is what I'd considered before but the problem is that it won't work until the little bubble turns green and I fear that would lead to confusion for the user. Maybe there could be two keystrokes: one that just runs a fixed set of modules and one that runs the ones at th epoint and the second keystroke could somehow indicate it wasn't ready to run somehow if the information about that mapping wasn't present?
@GrinDeg If you're feeling spammed by this issue discussion being so long, for your simple question, I apologize. Remember you can click its
Unsubscribe
button in the GitHub web site UI! smile
@greghendershott Thank you so much! It's ok :D
re "It just looks for module/module*/module+ forms in the source, textually ...": oh. I'm not excited to add that to DrRacket
OK. :man_shrugging:
To be clear, by "textually" I mean it walks the Emacs "syntax-propertized" buffer structure --- possibly similar to a color-lexer
. So it is not finding rando things like "level"
in a comment ;; find all (module level) bindings
.
But it won't work e.g. on #lang
s that let you define submodules but don't use sexprs. Someday maybe a Racket Mode user will point out any such example that matters to them, and maybe I'll try to deal with that then. Meanwhile, the feature seems useful to at least a few Racket Mode users.
Maybe this is a case where the perfect-forever might be the enemy of the good-for-the-forseeable-future. Of course that's my opinion based on my priorities.
As for check syntax reporting something about a mapping from source locations to submodules, that is what I'd considered before but the problem is that it won't work until the little bubble turns green and I fear that would lead to confusion for the user. Maybe there could be two keystrokes: one that just runs a fixed set of modules and one that runs the ones at th epoint and the second keystroke could somehow indicate it wasn't ready to run somehow if the information about that mapping wasn't present?
That could work. Also assuming the old annotations from a previous check-syntax are not immediately invalidated by a user editing, and assuming they're "sticky" and move with text after insertion or deletion (as with emacs text-properties): It is highly likely they will remain useful after the initial background check. So there might be an initial disable state, but maybe only until the first check-syntax finishes. That wouldn't be too bad.
@GrinDeg I pushed commit f80d48c for this. However it is on a check-syntax
branch that I've been working on nearly full-time for the last two months. It was cleaner for me to do it that way, because it's in some code that was changing and getting cleaned up, already. I hope to merge to master
, before too much longer. Anyway, this issue will auto-close once it is merged to master
, but if you have any questions feel free to let me know even after that happens.
re "It just looks for module/module*/module+ forms in the source, textually ...": oh. I'm not excited to add that to DrRacket
OK. 🤷♂
To be clear, by "textually" I mean it walks the Emacs "syntax-propertized" buffer structure --- possibly similar to a
color-lexer
. So it is not finding rando things like"level"
in a comment;; find all (module level) bindings
.But it won't work e.g. on
#lang
s that let you define submodules but don't use sexprs.Someday maybe a Racket Mode user will point out any such example that matters to them, and maybe I'll try to deal with that then. Meanwhile, the feature seems useful to at least a few Racket Mode users.
I agree it is useful! No doubt. That's not the issue. But since we're talking about it, I guess it does not work on things like (lambda (module) (module 'test))
?
I'm trying to move drracket in a direction where it is language agnostic which means finding solutions to problems like these in a language-agnostic way, not giving up on the problem.
Maybe this is a case where the perfect-forever might be the enemy of the good-for-the-forseeable-future. Of course that's my opinion based on my priorities.
Sure. Absolutely. No blame from me! :)
As for check syntax reporting something about a mapping from source locations to submodules, that is what I'd considered before but the problem is that it won't work until the little bubble turns green and I fear that would lead to confusion for the user. Maybe there could be two keystrokes: one that just runs a fixed set of modules and one that runs the ones at th epoint and the second keystroke could somehow indicate it wasn't ready to run somehow if the information about that mapping wasn't present?
That could work. Also assuming the old annotations from a previous check-syntax are not immediately invalidated by a user editing, and assuming they're "sticky" and move with text after insertion or deletion (as with emacs text-properties): It is highly likely they will remain useful after the initial background check. So there might be an initial disable state, but maybe only until the first check-syntax finishes. That wouldn't be too bad.
Totally!
Closed via commit 5226366.
When I try
_
lang lindenmayer
axiom
A
rules
A -> AB B -> A
variables
n=3
_
(https://docs.racket-lang.org/lindenmayer/A_Quick_Introduction_to_L-Systems.html)
It works and gives answer ABAAB
But when i try (https://docs.racket-lang.org/lindenmayer/Interpreting_L-systems.html)
lang lindenmayer racket
axiom
X
rules
X -> F[+X]F[-X]+X F -> FF
variables
n=7 θ=20 (require lindenmayer/turtle) (provide (all-from-out lindenmayer/turtle) X) (define (X turtles variables) turtles)
(it should draw image, and it DrRacket it does)
but it shows nothing in the REPL.
Is this normal? Can i make it show the image?
Omg, sorry for formatting