How to run interactively from terminal?

In my code I have a function that I would like to call while in the REPL in my macOS Terminal. I start my code like this: racket -i my-code.rkt

However, if I try to execute my function, doing (my-fun), I get this error message:
my-fun: undefined;
cannot reference an identifier before its definition
in module: top-level

When I'm in DrRacket, I can execute (my-fun) interactively without a problem.
What am I missing?

Probably what you need is ,enter (but maybe there are better methods).

$ grep -A4 '(define (sort-tasks' task.rkt   # `task.rkt` contains the `sort-tasks` function.
(define (sort-tasks tasks sort-specs)
  (for/fold ([sorted-tasks tasks])
            ([sort-spec (reverse sort-specs)])
    (sort sorted-tasks (make-task-sort-func sort-spec))))

$ racket -i task.rkt
Welcome to Racket v8.4 [cs].
> sort-tasks
sort-tasks: undefined;
 cannot reference an identifier before its definition
  in module: top-level
 [,bt for context]

> ,enter "task.rkt"
> sort-tasks
#<procedure:sort-tasks>

Since ,enter also requires the module, the -i task.rkt on the command line isn't necessary, so you can just start the REPL with racket and use ,enter with the module name inside it:

$ racket
Welcome to Racket v8.4 [cs].
> ,enter "task.rkt"
> sort-tasks
#<procedure:sort-tasks>

Edit: As shown in my other comment, in this context using the -t option is much more straightforward. One of my use cases for ,enter is to enter a test module that is defined inside the module I'm working on.

This is simpler:

$ racket -i -t task.rkt
Welcome to Racket v8.4 [cs].
> sort-tasks
#<procedure:sort-tasks>

Edit: Another relatively straightforward approach is to use require interactively:

$ racket 
Welcome to Racket v8.4 [cs].
> (require "task.rkt")
> sort-tasks
#<procedure:sort-tasks>
1 Like

Thanks a lot, sschwarzer! I prefer your racket -i -t task.rkt way, but it seems the code in task.rkt will also need a (provide sort-tasks) for that procedure to be available in the REPL.

I checked that and it seems to be true. The method with ,enter still works, though.

I would say that the choice of -t or ,enter depends on your situation. If this is a finished piece of code that you want to make it possible to call from the command-line, then go ahead and provide the function and use -t (it's worth noting that there is an (all-defined-out) form for provide that allows you to export all defined functions). The ,enter form is more of a debugging-repl kind of operation.

2 Likes

When using the -i -t options it seems to be impossible to in addition give a filename for a file from which to read data. I've tried things like this: racket -i -t my-code.rkt --data my-data.txt
Then I just get: racket: bad switch: --data
Is there some easy way around this?

Put -- to end the arguments interpreted by racket and leave the rest for your program to handle. So

racket -i -t my-code.rkt -- --data my-data.txt

I think the rule is this: If the first argument to racket is an option (starts with -), then racket processes all of the arguments and options up to --, then it puts the rest in (current-command-line-arguments). If the first argument to racket is not an option, it is assumed to be a Racket program (module), and all of the remaining arguments are put in (current-command-line-arguments).

3 Likes