v hyper.dev · seed - 0 - freedom of expression, and the spirit of John Shutt’s Kernel

Picture from instagram via midjourney.

If you find Scheme boring, without creativity, and dare challenge without fear the gentle, hot and firm burn of minimalism^W barely understood devices such as procedural pattern matching, gamma, vau, and statistics gathered on-the-fly to configure lowering at runtime that may be wholly, and fully localized, user defined, packaged, and re-used1.

Even if those are readily source available by your favorite brute force army. There is a parenthetical take: Kernel, and Futamura. Read on.

Kernel is the other programming interface that I can not take my mind away from. I tried. I failed. I failed many times. I failed Babelia because Kernel. I worked hard. I failed. I still dare recalling my failure. And nowadays, I do not shy away anymore. I dare claim it is not only elegant, it is beautiful. It takes more head space than any other language, standard, or (parenthetical leaning) implementation. It seems to me there is enough material for one to beam gamma rays to alphas for inspiration for decades, maybe centuries!

The primo, and ultimo goal: control a little more than Sun core.

Big Equation

Previously I called the following John Shutt’s equation of software. To keep any error my own, and because it goes against the grain, I intend to not mention him outside reference, and thanks. May his arguments always be properly evaluated.

The purpose of that equation is to describe enough of a system, and deliver enough material to support engineered discourse. Here are the three branches of seed’s eval:

(define (eval xp env ctx)
  (cond
   ;; If the expression `XP` is a symbol, return the object that is
   ;; associated with it in the environement `ENV`...
   ((symbol? xp) (environment-ref env xp))
   ;; If `XP` is a construction, try to apply it
   ((pair? xp)
    (define combiner (let ((prefix (car xp)))
                       (if (combiner? prefix)
                           prefix
                           (environment-ref env prefix))))
    (cond ;; Most likely combiner class, what is returned by lambda
     ((applicative? combiner)
      ;; Evaluate arguments `(cdr XP)`, hopfully mere environement-ref.
      (let ((xp+ (map (lambda (x) (eval x env ctx)) (cdr xp))))
        (apply combiner env ctx xp+)))
     ((operative? combiner)
      ;; The arguments `(cdr XP)` are passed as is, most likely, but
      ;; not only: symbols, numbers, booleans, and constructions...
      (apply combiner env ctx (cdr xp))))
    ;; ... not only self-evaluating!
    (else xp)))

The variable ctx hold the current flow of execution, to make it possible to migrate across hardware frontiers.

Small Demo

Download the small demo at hyper.dev.

Glimpsing over

Combiners returned by vau make it possible, and easy to hook into compilation machinery, that is without more time spent on a wood bank.

when

Here is the when:

(define when
  (vau (object . xps) env
      (if (eval object env)
          (eval (list* sequence xps) env)
          (void))))

Mind the fact that it works better if you do not know what a macro is, what compilation hooks are, and when you are not parenthetical phobic. Some familiarity with Scheme standard, R4RS, or R5RS helps.

It can be used like:

(when signal
  (reply 2006))

At somepoint, the previous procedure definition of when will be called. Using beta-reduction, and the fact that only signal, and replay are lexically scoped:

(if (eval 'signal env)
    (eval (list* sequence (list 'reply 2006)) env)
    (void)

Only object, xps were copy-pasted as a construction, and self-evaluating objects like symbols. In env, the symbols 'signal, and 'reply are bound. When (eval 'signal env) is processed, it returns for instance 101. That yields the following sequence:

(if 101 ;; that is not flasy
    (eval (list* sequence (list 'reply 2006)) env)
    (void)

Then:

(eval (list* sequence (list 'reply 2006)) env)

That is evaluated at call-site to the same object as the following expression:

(reply 2006)

Anaphoric When

Anaphoric when will bind the condition, called object in the above definition, to a variable inside the body. That is similar to walrus operator. An anaphoric when can be implemented with:

(define anaphoric-when
  (vau (variable object . xps) env
    (define tmp (eval object env))
    (if tmp
        (eval (list* sequence xps)
              (environment-cons env (list (cons variable tmp))))
        (void))))

It is supposed to be used in cases where the test condition is cpu heavy:

(anaphoric-when signal (+ 2006 (- 1337 42))
        (reply signal))

Similar to when, the use of anaphoric when is mostly lexically scoped. The applicative eval takes an environment as argument. The definition of anaphoric-when needs the object associated with the symbol object when anaphoric-when is used, hence the first line (define tmp (eval object env)) where ENV is the environment where anaphoric-when is used.

The main difference between when and anaphoric-when is that anaphoric adds the condition object inside the environment where the body of anaphoric-when is evaluated.

Again, describing a beta-reduction sequence:

(define tmp (eval (list '+ 2006 (list '- 1337 42)) env))
(if tmp
    (eval (list* sequence (list 'reply 'signal))
          (environment-cons env (list (cons 'signal tmp))))
    (void))
(define tmp 3301)
(if tmp
    (eval (list* sequence (list 'reply 'signal))
          (environment-cons env (list (cons 'signal tmp))))
    (void))
(if 3301 ;; not falsy
    (eval (list* sequence (list 'reply 'signal))
          (environment-cons env (list (cons 'signal 3301))))
    (void))
(eval (list* sequence (list 'reply 'signal))
      (environment-cons env (list (cons 'signal 3301))))
  1. The previous s-expression will be evaluated at call-site to the same object as:
(reply 3301)

That is echo.

Why

Unlike define-macro, and even more so hygienic syntax transformers, the approach of f-expr using vau makes it possible to re-use existing knowledge of how to program. It may be possible to re-implement the industrial macro machinery of modern implementations, but do we really want that?

Conclusion

I will write a procedural match ie. a pattern matcher, then see where to go from there. I think publicly distributed, and localized code are more helpful, than any other projections.

By the way, while I am at looking forward, take a look at GRASP, The GRAphical Scheme Programming Environment, look at the videos. I also recommend the answers by the same author on quora.

Regarding Futamura projection, it appears it is still interesting, and good material to build a new implementation of Scheme. After reading pebook, it is certain that it is a lot of work.

A time for yoga.

  1. may be known as up-coming long awaited next AAA release.↩︎