[plt-scheme] Apply a procedure in a module

From: Eli Barzilay (eli at barzilay.org)
Date: Mon Oct 12 17:13:31 EDT 2009

On Oct 12, Synx wrote:
> I'd like to know how to invoke mzscheme or mred or the like, so that
> I can run a specific procedure inside a specific module. What I have
> is a situation where I make a do-something.ss file/module and it
> contains something useful to import for do-something-else.ss, so I
> end up having to remove the toplevel procedure application from
> do-something.ss and instead make do-do-something.ss which contains a
> pretty carbon copy form of this:
> ---
> #lang scheme/base
> (require "do-something.ss")
> (main)
> ---
> Two things about that strike me as not a good idea. First off having
> toplevel procedure application at all is ugly,

It's perfectly fine to do that.

> and the only reason I do is because I can't specify a procedure to
> apply on the command line.

You can use `--main' to have the `main' function applied on the list
of command-line arguments.  For example, try this:

  exec mzscheme -um "$0" "$@"
  #lang scheme
  (provide main)
  (define (main . args)
    (printf "Arguments: ~s\n" args))

But it's better to do that using scheme/cmdline, for example:

  #!/bin/env mzscheme
  #lang scheme
  (let ([a "A"] [b "B"])
     [("-a" "--hay") a-val "blah blah" (set! a a-val)]
     [("-b" "--bee") b-val "blah blah" (set! b b-val)]
     #:args stuff
     (printf "A: ~s\nB: ~s\nArguments: ~s\n" a b stuff)))

> Secondly it means I have a bunch of redundant nearly identical files
> that do nothing besides import a module and apply its procedure. I'd
> like to have something instead the likes of:
> $ mzscheme -n -t do-something.ss -e '(main)'
> ...and not need to bother manually writing out a do-do-something.ss file
> at all.

You can use the above and use an argument to dispatch to some function
to run -- using scheme/cmdline will make it easy to do this reliably
(for example, using `#:once-any' to choose exactly one mode).

> Another advantage to doing that is it would enable me to be more
> flexible with regard to program entry points. This is very convenient
> especially for testing, and in my opinion is more expressive.
> Trouble is, I don't know how to do it. :(
> $ mred -n -t prompt.ss -e '(watch-forever "/var/tmp/bink")'
> #f::0: compile: bad syntax; function application is not allowed, because
> no #%app syntax transformer is bound in: (watch-forever "/var/tmp/bink")

If you really insist on doing this, you will need to have the bindings
from `scheme' available.  Here's one way to do this:

  #lang scheme
  (provide (all-from-out scheme))
  (provide foo)
  (define (foo x)
    (printf "foo: ~s\n" x))

and you can now run it with

  mzscheme -t that-file.ss -e '(foo 123)'

But it's better to avoid the module providing the scheme bindings, and
instead require them yourself -- drop that first `provide', and run

  mzscheme -l scheme -t $f -e '(foo 123)'


  mzscheme -lte scheme $f '(foo 123)'

          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                    http://barzilay.org/                   Maze is Life!

Posted on the users mailing list.