laurent.orseau
2021-3-3 08:41:10

Thanks for taking the time to do this, Stephen! The detail level is pretty good for really-new users. I think that can be very helpful for them.

If you are (or someone else is) willing to take another shot, I have a few requests: • Sound volume is very low, I can barely hear you at max volume. • 9mn is too long. Do you think this can be cut down to 1:30–2mn at most? • Do It For Real: Don’t pseudo-download, pseudo-install—you need to explain that you’re not doing it for real and why and what actually happens when you do it for real, which is unnecessary noise for the really-new users. For the parts that take too long, post edit the video to make it play at 4x, or merely cut the long portions (while saying so) possibly with a fade-out fade-in or something. • Don’t show multiple ways to do things (unnecessary information/noise), e.g., choose a language: just go straight at the bottom left button. I also find the “get guidance” box to be confusing—"What do I need to do here?". The list of languages with checkboxes is much clearer. Do explain “student” vs “non-student” as you’re doing, though. • Don’t show the Credits/Help desk. Instead, type something like (displayln "Hello, world!") in the top editor and click Run to demonstrate that everything works. • Depending on how easy it is to do for you, can you add captions? This would help non-native English speakers, as well as auto-translate to other languages. I realize I’m asking for a lot while you’ve already done a lot, so no worries if you won’t make another shot.

Side note: Installing on Linux is almost instantaneous (apart from the raco setup part), how come copying files takes so long on Mac?


laurent.orseau
2021-3-3 10:01:23

Mac Users: Is it possible to associate a file like my-program.rkt with the Racket executable so that double-clicking on my-program.rkt will run it with Racket?


soegaard2
2021-3-3 10:05:41

Yes. In Finder, right click the file and choose “Get Info”. Now change “Open with” and click the “Change All…” button. But I think this happens automatically during installation?


laurent.orseau
2021-3-3 10:06:47

So by default the association is with DrRacket then?


soegaard2
2021-3-3 10:06:57

I believe so.


laurent.orseau
2021-3-3 10:07:22

Is there an easy way to make it run with Racket without breaking the association with DrRacket?


laurent.orseau
2021-3-3 10:07:28

Like a launcher?


soegaard2
2021-3-3 10:07:53

Don’t know.


laurent.orseau
2021-3-3 10:14:51

Then maybe the right thing is to do “DrRacket | Racket | Create executable | Create launcher” …


spdegabrielle
2021-3-3 11:00:47

Windows has multiple actions associated with a file type, e.g. edit and run, with a default action. E.g. a Remote Desktop file type (.rdp) defaults to the run action. I’m not sure what, or if, there is an equivalent in macOS. (Or Linux for that matter)


spdegabrielle
2021-3-3 11:01:16

I’ll check


spdegabrielle
2021-3-3 11:03:26

Nevermind - there is no point in configuring a generic run action because you won’t know if it is a gracket file from The file type


laurent.orseau
2021-3-3 11:05:12

gracket doesn’t matter nowadays. At least on my machine, I tried checking “racket” instead of “gracket”, and it still figures out that it’s gui, even if the file is merely #lang racket/base (require some-gui-stuff) . So pretty cool :slightly_smiling_face:


spdegabrielle
2021-3-3 11:24:47

I wonder if gracket can be removed then?

Does gracket (and the select launcher option) count as an <https://felleisen.org/matthias/manifesto/sec_intern.html|Extra-Linguistic Mechanism> that is already internalised by #lang ...+(require ...)?


laurent.orseau
2021-3-3 11:30:14

If it’s possible to remove it, I certainly vote for this.


spdegabrielle
2021-3-3 11:38:11

I’ve never tried to make my own custom racket distribution - the instructions are available in considerable detail - I’ve often thought about a racketeers edition that • cuts the teaching langs, • adds (my favourite) quickscript scripts by default, • and splits run into three buttons, profile, debug, and run. • Includes racket-templates by default • Includes a bunch of other plugins you don’t want in the education edition • Adds a racket-mode installer that sets up Emacs


spdegabrielle
2021-3-3 11:40:01

But is is probably easier to just ask the core team if gracket can be removed?


soegaard2
2021-3-3 12:42:58

Isn’t gracket used for … something .. on Windows? Maybe to allow programs with guis from the terminal?


laurent.orseau
2021-3-3 12:55:05

In that case, is there anyone on windows who can try the following: File mod1.rkt: #lang racket/gui (message-box "Hey you!" "Yop!") File mod2.rkt: #lang racket/base (require "mod1.rkt") When file mod2.rkt is in the current tab in DrRacket, click on “Racket | Create an executable…” then select “Launcher” and select racket (not gracket). Click on Create.

Open the file explorer, and double click on the newly created executable. Do you see the message box or does it throw an error, or does nothing happen at all?


hectometrocuadrado
2021-3-3 13:03:38

Here!


mflatt
2021-3-3 13:07:28

Windows and Mac OS both make a distinction between GUI executables and command-line executables. (On Windows, it’s a bit in the “.exe”. On Mac OS, it’s an “.app” bundle versus a plain executable.) There are various effects from that distinction, such as the icon used in Finder on Mac OS, the difference in what happens when you double-click from Finder, and the way I/O is handled on Windows even if you start from a command prompt.


laurent.orseau
2021-3-3 13:09:55

Wonderful, thanks @hectometrocuadrado! So it works but it opens a terminal then. I suppose if you select gracket instead, the terminal doesn’t show up?


hectometrocuadrado
2021-3-3 13:11:22

You’re right


laurent.orseau
2021-3-3 13:11:31

great, thank you


hectometrocuadrado
2021-3-3 13:11:43

No problem :D


laurent.orseau
2021-3-3 13:12:16

Oh, that makes things more complicated to explain then. :thinking_face: Maybe the simplest route is to make the user check gracket by default? But then if it’s a terminal interaction program, that won’t work at all…


laurent.orseau
2021-3-3 13:16:09

Ah, wait, are the differences still that big when choosing “launcher” instead of “stand-alone”?


laurent.orseau
2021-3-3 13:16:43

(I’m intrigued by the I/O part)


mflatt
2021-3-3 13:35:31

Yes, the differences are the same with launchers.


mflatt
2021-3-3 13:40:01

On the I/O part: For example, if you run “DrRacket.exe” in command prompt on Windows, then the prompt comes back right away as DrRacket starts. If something in DrRacket tries to write to stdout or stderr at the OS level, it would go nowhere. (But GRacket arranges for output to the initial current-output-port or current-error-port to go to an application-specific console window, instead of going to the nowhere stdout and stderr.)


laurent.orseau
2021-3-3 14:12:31

I see. Would you say that choosing gracket is a safer default choice than racket then?


mflatt
2021-3-3 14:15:54

I’m not sure there’s a safe default, but racket seems like a simpler default.


laurent.orseau
2021-3-3 14:19:04

Will gui apps still work correctly on all platforms if racket is selected? Albeit with an additional console window maybe (on Windows at least, no idea about mac).


mflatt
2021-3-3 14:22:00

GUI apps will still run, although they may not interact with the environment in quite the right way, such as starting up without opening a terminal window.


laurent.orseau
2021-3-3 14:26:11

Great. As long as they work, it should be okay. I can add a line about the terminal window


hazel
2021-3-3 15:08:23

@philip.mcgrath does Guix not have /bin/sh?


hazel
2021-3-3 15:08:42

Nix keeps /bin/sh and /usr/bin/env (and nothing else) for compatibility’s sake


philip.mcgrath
2021-3-3 15:31:58

@hazel It usually would in profiles, but not in isolated environments (IIUC). But Nix also patches things like #!/nix/store/k6b8xc55g3sj35jn3qm95yag1i6j6mbc-ruby-2.6.6/bin/ruby


hazel
2021-3-3 15:32:59

I’m aware, but Nix keeps /bin/sh regardless


hazel
2021-3-3 15:33:11

also, thank you for making the PR that I was slightly too scared to :slightly_smiling_face:


sorawee
2021-3-3 15:36:59

I don’t think this is a good idea. Makes it easy for malicious code to be run accidentally.


philip.mcgrath
2021-3-3 15:45:49

I’d actually been looking at it before I saw your issue!


laurent.orseau
2021-3-3 15:46:23

hazel
2021-3-3 15:46:35

this was sparked by me trying to compile Racket from Git on NixOS and @samth watching me suffer


philip.mcgrath
2021-3-3 15:47:24

I guess a difference is that most Guix-specific build scripting is in Scheme rather than Bash, so maybe it’s less dependent on /bin/sh and /usr/bin/env to get started? (I don’t really know.)


hazel
2021-3-3 15:47:43

I mean Nix uses a DSL but the builders still end up being bash, yeah


hazel
2021-3-3 15:48:49

annoyingly I also have to keep the $LD_LIBRARY_PATH that I set during build to get my compiled Racket to run. but I’ll cope


philip.mcgrath
2021-3-3 15:53:59

Guix patches “collects/db/private/sqlite3/ffi.rkt”, “/collects/openssl/libssl.rkt”, and “collects/openssl/libcrypto.rkt” with the absolute paths to the libraries. Might work for Nix, too? (Though I don’t think it’s an especially elegant solution.)


hazel
2021-3-3 15:54:41

Nix uses a wrapper that sets $LD_LIBRARY_PATH before running Racket, which is probably cleaner


hazel
2021-3-3 15:55:05

what I did is I wrote shell scripts that are called racket, raco, and drracket that set $LD_LIBRARY_PATH and then execute the actual Racket binary


samth
2021-3-3 17:00:18

it seems like neither absolute paths nor wrapper shell scripts ought to be required. do nix/guix have sensible solutions that other languages use? or is this a “non-c languages are second class citizens” story?


ben.knoble
2021-3-3 17:18:07

Does anyone have thoughts on how to implement global defines in an environment-passing interpreter with immutable environments? Think upper-level university students, so nothing too crazy. (Running into the issue that the eval-define can’t affect the env used for future eval calls; it only has a name and expr to bind to that name.)


samth
2021-3-3 17:33:25

What do you mean by “global defines”? In particular, do you have the whole program and you want to implement defines that scope forward in the program (like in a Racket module), or are you trying to simulate something like the REPL?


philip.mcgrath
2021-3-3 17:36:02

That’s one of the things I’m looking into (but only for, like, a couple weeks). I don’t think they’re on Slack, but Chris Lemmer Webber got me interested in a Racket to Guix package auto-importer like they have for other languages.


ben.knoble
2021-3-3 17:36:17

I have the whole program as a parse-tree (sort of a tagged racket list). But the grammar rule for define is just define := DEFINE NAME expr ; define is a kind of expr , and a program is a series of exprs.

Our goal is to have a define always create a global binding (i.e., the binding is scope for the rest of the program, even for non-top-level defines). The result of a define expr is just the value of the “body” expr, as it were.

So, more the former than the latter, if that helps.


samth
2021-3-3 17:36:52

This seems like a separate issue from creating packges, though.


philip.mcgrath
2021-3-3 17:39:23

In Guix (I haven’t looked “under the hood” much in Nix), a lot of things do seem to be patched to use absolute paths. In my cursory search of the mailing list, it sounds like some of them have something against LD_LIBRARY_PATH that I don’t understand. But there is a “search path” mechanism that seems like it should be a better way to support Racket, though I don’t fully understand it yet. After all, Guix is Guile all the way down, and they are certainly dynamically linking somehow.


philip.mcgrath
2021-3-3 17:40:56

But I think the extent of Racket packaging in Guix so far is just to get racket working on the path of least resistance. For example, the minimal package is defined as a variant of the main distribution with a different source tarball, vs. being in essence raco pkg install main-distribution.


samth
2021-3-3 17:57:38

So then you should probably do the following: 1. Collect all the defines from the program at the beginning and create an environment that includes all those names 2. Use that environment as the initial environment for your program 3. When you evaluate a define, also update the environment (I know you said immutable but that is not going to work)


ben.knoble
2021-3-3 18:14:56

Hm. I’m not sure how that would work here; (1+2) would allow reference to the names before the defines, needing some special tagging to say “not defined yet”; (3) might not update the right environment, since there’s no “chaining” lookups—when binding’s are added, it’s simply hash-set , which can’t be mixed with hash-set!—that would make all env’s mutable… Thanks for the input, but I think we’re hoping for a simpler strategy.


samth
2021-3-3 18:16:50

Well, what do you want this program to do? (define even? (lambda (n) (if (zero? n) true (odd? (- n 1))))) (define odd? (lambda (n) (if (zero? n) false (even? (- n 1)))))


ben.knoble
2021-3-3 18:18:04

Great point, except that the lambda bodies aren’t evaluated. Wouldn’t that work just fine, since the body is evaluated at use (say, even? 5), after which odd? is already defined?


samth
2021-3-3 18:18:35

no, because lambda should remember the environment that it was evaluated with (that’s what lexical scope requires)


ben.knoble
2021-3-3 18:18:37

ah, except closures… so the environment has no binding for odd?


ben.knoble
2021-3-3 18:18:44

yea, got there a minute too late


samth
2021-3-3 18:18:48

:slightly_smiling_face:


samth
2021-3-3 18:20:59

I think the short answer is that the complexity of what I described is fundamental to what “define” usually means.


ben.knoble
2021-3-3 18:22:19

yeah, that’s fair. we haven’t covered anything of that complexity, and unfortunately i don’t think we have room in the assignment for it (but we would like to have it for the next assignment, too, and we don’t have room to implement it there. Ugh. tries to remember how he did this when implementing a lisp in java for a past version of the course


dvanhorn
2021-3-3 21:28:56

If definitions only occur at the top-level and are always functions, you can consider there to be two kinds of variable references: one to local, lexical variables and one to globally defined variables. In addition to the normal environment, you have the top-level environment that maps define names to their expressions and Sam’s example should work out fine. No mutability or cyclic environments needed.


ben.knoble
2021-3-3 21:33:58

@dvanhorn yeah, we’re starting to consider what modifications we can make to the semantics and grammar to make this feasible. I think we’ve settled on top-level only (which we can fix in the grammar); we’d like to avoid having two conceptual environments, but I think this requires somebody to return the (possibly extended) environment in order to correctly affect future evaluations. OTOH, if we also assume no mutual recursion, very “C”-like (no forward decls either), we get something that more or less works? (it’s not industrial, but it’s for a class…)


samth
2021-3-3 22:42:25

If you want regular recursion you still need to do something


dvanhorn
2021-3-3 22:44:15

well actually…


dvanhorn
2021-3-3 22:44:46

Here’s a sketch of what I was saying: #lang racket (define (eval-prog p) (match p [(list ds ... e) (eval-expr e '() p)])) (define (eval-expr e r p) (match e [(? symbol? x) (if (bound? r x) (lookup r x) (eval-expr (global p x) '() p))] [(? boolean? b) b] [(? integer? i) i] [(list 'zero? e1) (zero? (eval-expr e1 r p))] [(list 'sub1 e1) (sub1 (eval-expr e1 r p))] [(list 'if e1 e2 e3) (if (eval-expr e1 r p) (eval-expr e2 r p) (eval-expr e3 r p))] [(list 'λ (list xs ...) e) (λ vs (eval-expr e (append (zip xs vs) r) p))] [(list e es ...) (apply (eval-expr e r p) (map (λ (e) (eval-expr e r p)) es))])) (define (zip xs vs) (match xs ['() '()] [(cons x xs) (cons (cons x (first vs)) (zip xs (rest vs)))])) (define (bound? r x) (assq x r)) (define (lookup r x) (cdr (assq x r))) (define (global p x) (match p [(list (list 'define y e) ds ...) (if (eq? x y) e (global ds x))])) (eval-prog '[ (define even? (λ (n) (if (zero? n) #t (odd? (sub1 n))))) (define odd? (λ (n) (if (zero? n) #f (even? (sub1 n))))) (odd? 100) ])


sorawee
2021-3-3 22:47:56

dvanhorn
2021-3-3 22:49:39

yep, same idea in reduction semantics form


ben.knoble
2021-3-3 22:49:43

Samth is right, because of closures, without some special support for the name of the closure—even that code does some handling for global names, though it’s O(n) or worse


dvanhorn
2021-3-3 22:51:06

you can easily make global a O(1) operation if that’s the problem.


spdegabrielle
2021-3-3 22:51:24

New users installing on Linux have to navigate the minefield that is their own package management system installing a version of racket that is between 2 and 5 years old.

A video is needed for Linux too.

From the recent raspberry pi hooha I‘ve gathered big oss(lol) projects like VScode can have their own repo and GPG key in your apt config; apparently this is how you remove it:

sudo rm /etc/apt/sources.list.d/vscode.list sudo rm /etc/apt/trusted.gpg.d/microsoft.gpg I’m not a big Linux user and I don’t have my rpi Rn but I do wonder if we could hosting the apt package locally would make it easier to deploy new versions? Ie /etc/apt/sources.list.d/racket.list /etc/apt/trusted.gpg.d/plt.gpg


spdegabrielle
2021-3-3 22:52:41

Assuming you use apt, What does a .list file in /etc/apt/sources.list.d/ contain?


samth
2021-3-3 22:52:43

Sure I just mean you need either your global idea or recursive environments


dvanhorn
2021-3-3 22:52:49

But yes, you don’t have a general letrec form here (but this is the untyped lambda calculus so programming with recursion even without globally defined things is still possible). If you want letrec I think you have to bite the bullet and introduce cyclic data structures to represent closures that are self referential


ben.knoble
2021-3-3 22:52:56

Not really a problem, just something that occurred to me (is the O(1) version just a pre-traversal to collect globals?). I will let y’all know what we come up with, and thanks for the absolutely fascinating discussion! Loving it


dvanhorn
2021-3-3 22:53:19

yeah, make it a hash table from defined names to expressions.


ben.knoble
2021-3-3 22:53:32

Yeah i dont think we’re planning on doing letrec. Though recursive defined might be nice; I’ll have to ask.


spdegabrielle
2021-3-3 23:04:35

As for the video 1. you can add captions in YouTube 2. a short demo is good maybe a three line webserver 3. just show Lang selection on first run 4. Explain the difference between teaching languages and racket 5. do it for real takes a long time (I can’t edit video on the Mac) 6. sound louder 7. 2 minutes lol My barrier is I don’t have video editing tools - I just have a copy of Camtasia on a work windows 10 machine. No video editing on the Mac just capture with obs.


ben.knoble
2021-3-3 23:06:08

Yep, we did recursive environments in the past. (It was more like common lisp than racket, with setq, defun, non-closure lambda and closure function.) i’m having a hard time if the recursion in envs enabled recursive defun, or if the mutation of the closure-captured environment to also store the name->function binding made it work.

In fact, wouldn’t we be able to support recursion only in defines by reaching in and tweaking a closure’s env to include the self-referential name? Or is there a circularity knot that needs tied there? (Argh, maybe; you want to extend the env with a name bound to the closure which should have its env extended with a name bound to the closure which… perhaps you have to in fact extend the env with something that evaluates to the correct (recursion-enabled) closure when referenced, rather than creating it first? Still might be circular. Darn. )


shu--hung
2021-3-4 04:42:09

I am confused about this define. Is it really meant to be a one-element let rec (like in OCaml), instead of the common interpretation of define?

that is, the same as let rec f x = body


hazel
2021-3-4 06:35:37

the issue with Nix and LD_LIBRARY_PATH for anything is that oftentimes different packages will require different LD_LIBRARY_PATHs. like, one package can depend on library 1.1.1, the other can depend on a somehow incompatible 1.1.3, but the shared objects have the same filename for some accursed reason


hazel
2021-3-4 06:37:31

this sometimes occurs when, for example, NixOS unstable updates glibc or something major, but the stable version of NixOS doesn’t. it’s possible to mix and match the stable and unstable distribution because of this, despite the libc upgrade


hazel
2021-3-4 06:38:30

basically the idea is that different packages inherently need different environments w.r.t versioning, especially re:ffi


hazel
2021-3-4 06:38:41

but also please understand that I never actually know what I am talking about