awwx.ws

implicit2

Implicit variables

http://awwx.ws/implicit2.arc:

(mac implicit (name (o val))
  `(do (defvar ,name (scheme.make-parameter ,val))
       (mac ,(sym (string "w/" name)) (v . body)
         (w/uniq (param gv gf)
           `(with (,param (defvar-impl ,',name)
                   ,gv ,v
                   ,gf (fn () ,@body))
              (scheme (parameterize ((,param ,gv)) (,gf))))))))

Implicit variables are passed implicitly into function calls, instead of needing to be explicitly listed in the function arguments.

arc> (implicit foo)
#(tagged mac #<procedure: w/foo>)
arc> (def h ()
       (string "foo: " foo))
#<procedure: h>
arc> (def g ()
       (h))
#<procedure: g>
arc> (def f ()
       (w/foo 42 (g)))
#<procedure: f>
arc> (f)
"foo: 42"

They’re useful when, as in this example, the same variable is being passed through several layers of function calls.

Any program that uses implicit variables can be rewritten to pass the arguments explicitly, though you may need to add the argument to many intermediate functions.

arc> (def h (foo)
       (string "foo: " foo))
#<procedure: h>
arc> (def g (foo)
       (h foo))
#<procedure: g>
arc> (def f ()
       (g 42))
#<procedure: f>
arc> (f)
"foo: 42"

Likewise, any argument that is being passed explicitly can be passed implicitly instead, though the result may be unbearably tedious if the function is often called with arguments that are different.

arc> (implicit a)
#(tagged mac #<procedure: w/a>)
arc> (implicit b)
#(tagged mac #<procedure: w/b>)
arc> (def plus ()
       (+ a b))
#<procedure: plus>
arc> (w/a 3 (w/b 5 (plus)))
8

Unlike a global variable, setting the value of an implicit variable with its w/ macro doesn’t set its value everywhere, but only inside of the execution of the w/.

arc> (implicit foo 5)
#(tagged mac #<procedure: w/foo>)
arc> (def g () (+ foo 10))
#<procedure: g>
arc> foo
5
arc> (w/foo 10 (g))
20
arc> foo
5

Being “outside” the w/ macro includes not only exiting the w/ normally or with an exception, but also being outside with continuations or threads:

arc> (implicit foo 10)
#(tagged mac #<procedure: w/foo>)
arc> (do (thread (repeat 10
                   (prn "in thread: " foo)
                   (sleep 1)))
         (w/foo 5
           (repeat 5
             (prn "outside thread: " foo)
             (sleep 2))))
outside thread: 5
in thread: 10
in thread: 10
outside thread: 5
in thread: 10
in thread: 10
in thread: 10
outside thread: 5
in thread: 10
outside thread: 5
in thread: 10
in thread: 10
outside thread: 5
in thread: 10
in thread: 10
nil

You can also set the value of an implicit variable with Arc’s usual assignment forms such as = and ++. Such assignments will be visible to callers, but isolated within execution context of its w/ form.

arc> (implicit foo 10)
#(tagged mac #<procedure: w/foo>)
arc> (def g () (++ foo))
#<procedure: g>
arc> (w/foo 20 (g) foo)
21
arc> foo
10

I don’t know of an example of where this would be useful, but I didn’t see a reason to forbid it either.

Implementation

Implicit variables are implemented using MzScheme’s parameter feature. Arc’s stdin, stdout, and stderr are also MzScheme parameters, which is how for example tostring can be used in one thread without messing up the stdout of another thread.

In MzScheme to get the value of a parameter you call it as a function with no arguments, which is why in Arc to get the current value of stdout you use (stdout). This implemention uses defvar so that the value of an implicit variable can be referenced with simply foo instead of having to say (foo).

Acknowledgments

My thanks to rntz for help with this hack.

The w/foo macro form is inspired by Arc’s w/stdin and w/stdout.

Prerequisites

This hack depends on arc3.1, scheme0, and defvar2.

Get this hack

Using the hackinator:

$ hack \
    ycombinator.com/arc/arc3.1.tar \
    awwx.ws/defarc0.patch \
    awwx.ws/defarc-ac0.patch \
    awwx.ws/extend0.arc \
    awwx.ws/scheme0.arc \
    awwx.ws/defvar1.patch \
    awwx.ws/defvar2.arc \
    awwx.ws/implicit2.arc

License

Same as Arc.

Contact me

Twitter: awwx
Email: andrew.wilcox [at] gmail.com