Setting language with #lang in the REPL
Asked Answered
N

3

21

I would like to set the language in the REPL on the fly, with #lang, not using "-I" command-line argument. But this gives me the error "read: #lang not enabled in the current context".

Is there a command-line switch that I'm missing? Or maybe a ",metacommand" I can use? The reason I need this is because I would like to be able to send an Emacs buffer to the Racket REPL, but that won't work if the file starts with #lang.

Notepaper answered 8/1, 2014 at 23:16 Comment(0)
P
11

[Edit]

I can't get C-x C-b to work with #lang either.

But a buffer containing #lang can be sent to a REPL started from Geiser with C-c C-a. This is Switch to REPL and Enter Module from the Geiser drop down menu. If I have a buffer for bugsy.rkt:

;; bugsy.rkt
#lang racket
(define k 6)
(define j 7)
(define (f lhs rhs)
   (+ lhs rhs))

Typing C-c C-a gives me this in the REPL:

racket@> ,enter "<filepath>/bugsy.rkt"
[email protected]>

I can then access the module in the REPL:

[email protected]> k
6
[email protected]> (f 3 4)
7

If I want to switch to a different module [or buffer of a file] I can use the ,enter command in the REPL:

[email protected]> ,enter "clyde.rkt"
[email protected]> ,enter "bonny.rkt"
[email protected]>

There is an example of the ,enter command in the documentation. Look above the Dinosaur.

[Original]

According to the Racket documentation #lang has very simple syntax, the reader essentially bootstraps a language syntax from whatever follows the space character after #lang. This means in some sense that #lang is not in Racket's [or any other language's] syntax. Instead it is a implementation feature of the reader which forms part of the larger "Racket" development ecosystem.

Geiser [and presumably Quack and racket-mode] handle this by parsing #lang in elsip before passing code to the Racket REPL. In Geiser, the work is done in geiser-racket.el.

The parsing function is at line 132:

(defun geiser-racket--language ()
  (or (cdr (geiser-racket--explicit-module))
      (save-excursion
        (goto-char (point-min))
        (if (re-search-forward "^#lang +\\([^ ]+\\)" nil t)
            (geiser-syntax--form-from-string (match-string-no-properties 1))))
      "#f"))

And it is called by geiser-racket--geiser-procedure on line 166.

(defun geiser-racket--geiser-procedure (proc &rest args)
  (case proc
    ((eval compile)
     (format ",geiser-eval %s %s %s"
             (or (car args) "#f")
             (geiser-racket--language)
             (mapconcat 'identity (cdr args) " ")))
    ((load-file compile-file)
     (format ",geiser-load %S" (geiser-racket--find-module)))
    ((no-values) ",geiser-no-values")
    (t (format ",apply geiser:%s (%s)" proc (mapconcat 'identity args " ")))))

That may give you a starting point for rolling your own code if one of the existing Emacs modes does not meet your needs.

Pitiful answered 9/1, 2014 at 16:3 Comment(4)
So Geiser can transform the #lang directive into code runnable in Racket REPL, but where is this used? Certainly, running C-c C-b, geiser-eval-buffer, doesn't do this, it just passes #lang straight through, causing the same error as above. (Tested with an up to date Geiser from MELPA.)Notepaper
@DavorCubranic I have added additional information about the Geiser REPLPitiful
Thanks, this answers what I was really looking for. Although I may end up using @GregHendershott's racket-mode, as it's closer to the DrRacket experience.Notepaper
In geiser I can also enter a module, by [C-u C-c C-z], you can see explanations in this post: lists.nongnu.org/archive/html/geiser-users/2012-12/… , I have tried #lang racket and #lang web-server/insta and both worked as expected. Just note that I cannot do [C-u C-c C-z] in a scratch buffer -- I have to save the buffer into a named file at first.Knitted
C
5
; foo.rkt
#lang whatever
"hi"

is basically the same as

(module foo whatever
  "hi")

So as a quick hack you could probably slice off the #lang line, grab the lang out of it, and stuff the rest of the buffer inside of the (module ...) form before comint-send-input-ing it.

Even easier, if you don't mind saving the buffer to disk, first: Just send over ,enter /path/to/file.rkt to the REPL buffer, or if you're not using XREPL, (enter! "/path/to/file.rkt").

Also, it's worth mentioning a few Racket-related modes:

One of them might already do what you want, or, you could peek into how they work (each takes a somewhat different approach to this).

Cerelia answered 9/1, 2014 at 1:23 Comment(4)
Ah, racket-mode, looks just like what I need!Notepaper
For the record: When I wrote this answer, the question didn't mention Geiser. Later, someone else edited the question to add a Geiser tag, then wrote an answer based on that.Cerelia
@GregHendershott what is the best way to do this in racket-mode specifically? I'm trying to go through SICP with #lang sicp and am curious if this works easily with racket-mode.Vanillin
1. Create or switch to a buffer with a .rkt file. 2. Do C-c C-c aka racket-run. 3. Profit.Cerelia
V
1

I had a really hard time wrapping my head around this using Racket & Geiser to go through SICP with #lang sicp. Finally figured it out. Based on all the good answers above, these are comments to remind myself of what to do and why:

#lang sicp
;;C-c C-a loads #lang module into REPL (save before loading)
;;C-u C-c C-z is faster than C-c C-a
;;https://docs.racket-lang.org/sicp-manual/index.html
;;https://mcmap.net/q/606838/-setting-language-with-lang-in-the-repl
(#%require sicp-pict)
(paint einstein)

Racket and Geiser are two amazing pieces of software, almost gave up but it was worth the effort to get this working. Thanks to all for the good work and helping us learn.

Vanillin answered 2/4, 2018 at 14:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.