Parallel "expand".

Parallel "Expand"

Almost all Lisp dialects support both "parallel" and "serial" assignment operators like let and letn in Newlisp. For example

    (setf y 1)
    (let((y 2)(x y)) x)  ==> 1   (parallel)


   (setf y 1)
   (letn((y 2)(x y)) x)  ==> 2   (serial)

Expand-expression in Newlisp

   (expand '(x y) 'x 'y)

results in replacement of x and y in (x y) with values of x and y. Expand-expression in other form:

   (expand '(x y) ((x <value1>)(y <value2>)))

results in replacement of x and y in (x y) with <value1> and  <value2>.

In both cases, the replacement is performed in serial fashion. For  example,
   (expand '(x y) '((x y)(y 3))) ==> (3 3)

In this post I present the implementation of parallel expand,  expand// in Newlisp; two slashes in name remind on parallel lines such that, for instance

   (expand// '(x y) '((x y)(y 3))) ==> (y 3).

Parallel expand expression can be reduced to serial expand with introduction of new variables.

  (expand// <expr> '((<var1> <val1>)...(<varn> <valn>))) =

  (expand <expr> '((<var1>   expand//1) ... (<varn>   expand//<n>)
                   (expand//1 <val1>  ) ... (expand//n <valn>)))

Fexpr expand// can use always the same temporary variables expand//1, ..., expand//n, without need for generating fresh variables each time expand// is called. Other form of expand//,

  (expand// <expr> '<var0> ... '<varn>)

can be reduced on form

  (expand <expr>
         '((<var0>   expand//0) ...        (<varn> expand//<n>)
           (expand//0 <value of var0>) ... (expand//<n> <value of var<n>>))).

Using that idea, the implementation is not very technical

(define (expand// expr)
  (letn((a (args))
        (expand//sym (lambda(n)(sym (append "expand//" (string n)))))
    (if (empty? a)
        (throw-error "expand//: arguments missing.")

        (cond ((symbol? (first a))
               (append (map (lambda(i)(list i (expand//sym $idx))) a)
                       (map (lambda(i)(list (expand//sym $idx) (eval i))) a)))
              ((list? (first a))
               (append (map (lambda(i)(list (i 0) (expand//sym $idx))) (first a))
                       (map (lambda(i)(list (expand//sym $idx) (i 1))) (first a))))))))

       (println "expandlist=" expandlist)
       (expand expr expandlist)))

(setf x 'y)
(setf y 3)
(println (expand '(x y) 'x 'y))           ; => (3 3)
(println (expand// '(x y) 'x 'y))         ; => (y 3)
(println (expand '(x y) '((x y)(y 3))))   ; => (3 3)
(println (expand// '(x y) '((x y)(y 3)))) ; => (y 3)



"Nothing Will Happen" in Belgrade, April 2011

Nothing Will Happen in Belgrade, April 2011

I returned from another "Ništa se neće dogoditi" (Nothing will happen) hacker conference, this time in Belgrade, Serbia. As usually, the program was made on place on the base of existing supply and demand. No attendance fee. Lot of fun and enthusiasm. I didn't prepared presentation but as there was some interest in Lisp, I discussed some of the most popular topics discussed in this blog.

I forgot my camera, so I borrow few photos made by other participants.

Thanks to organizers.


Waiting for the start. I'm third from the left.


One presentation held in "Magacin."


One presentation held in bar.

See also "Nothing will Happen", Split, August 2010

One Picolisp Snippet.

One Picolisp Snippet


I had presentation on Picolisp in Hacklab "Mama" in Zagreb few weeks ago.

 Not that I'm expert in Picolisp, but I think I understand it well enough for short introduction. Picolisp is somehow Spartan dialect of Lisp - for example, it doesn't support floating point numbers, and it is not available on Windows - except by using VirtualBox or something like that. But it is dynamically scoped, and it supports some powerful and interesting features as fexprs, coroutines and anonymous symbols, integrated Prolog and database. It is particularly interesting that Picolisp doesn't have strings - the symbols are used for that purpose. On the first sight, absence doesn't look like advantage, but it is, because all usual functions defined on strings now work directly on symbols, without need for conversion.

As a bonus, Picolisp might be the fastest Lisp interpreter, written entirely (in 64 bit version) in assembly language.

The author of Picolisp is Alexander Burger; as Picolisp is, in spirit, very similar to Newlisp, we can almost speak about German school of Lisp. OK, maybe another similar Lisp "made in Germany" is needed for that.

The reactions on Picolisp and presentation were positive; Zagreb is one of the places where Lispers encourage each other, no matter of dialect. We had three days of "Clojure Fest" few months ago (unfortunately collided with swine flue fest.)

I don't want to allow you to go home without any code, so this was the most liked example from presentation.

: (setq my '(list 1 2))
-> (list 1 2)
: (intern (name (zap 'list) "popis")) # not a string
-> popis
: (popis 1 2 3)
-> (1 2 3)
: my
-> (popis 1 2)

Variable Definitions Supported in Clojure, Common Lisp, ISLisp, newLISP, Picolisp and Scheme.

Variable Definitions Supported in Clojure, Common Lisp, ISLisp, newLISP, Picolisp and Scheme

    variable constant
("immutable variable")
global lexical ISLisp (defglobal)
Scheme (define)
dynamic Clojure (def)
CL (defvar, defparameter)
ISLisp (defdynamic)
Picolisp (de)
Newlisp (define)
CL (defconstant)
ISLisp (defconstant)
Newlisp (define + constant)
local lexical CL (let, let*)
ISLisp (let, let*)
Scheme (let, let*, letrec, letrec*)
Clojure (let, let*)
dynamic Clojure (def + binding)
CL (let + declare special, def... + let)
ISLisp (dynamic-let)
Newlisp (let, letn)
Picolisp (let)

If I forgot something or made mistake, please, let me know.

Symmetric Support for Lexical and Dynamic Scope (Binding) in ISLisp.

Symmetric Support for Lexical and Dynamic Scope (Binding) in ISLisp.

In ISLisp, all combinations of global/local and lexical/dynamic operators for definition of variables are supported. If operator contains word "dynamic", then the binding will be dynamic. The operator 'dynamic' is needed for reference of such variables. Hence, ISLisp is only dialect of Lisp that allows all versions of standard example for explanation of difference between lexical and dynamic scope.
  1. Variable x is defined with lexical/dynamic global binding and value 1. The function f=(lambda()x) is defined on top level.

  2. Variable x is defined with lexical/dynamic local binding and value 2. The function f is called from the scope of that binding.
There are four combinations:
                                global binding of x in
                              place of function definition 

                                |  lexical  |  dynamic
                    ------------+ ----------+-----------         
local  binding of     lexical   |     1     |    1
x in place of       ------------+-----------+-----------
function call         dynamic   |     1     |    2
Here is the code:

(defglobal x 1)
(defun f()x)

(let((x 2))
  (print (f)))       ;=>1


(defglobal x 1)
(defun f()x)

(dynamic-let((x 2))
  (print (f)))       ;=>1


(defdynamic x 1)
(defun f()(dynamic x))

(let((x 2))
  (print (f)))       ;=>1


(defdynamic x 1)
(defun f()(dynamic x))

(dynamic-let((x 2))
  (print (f)))       ;=>2
ISLisp is simplified and on few places, like this one, improved Common Lisp. I must recommend the most mature implementation of ISLisp: Christian Jullien's Eligis OpenLisp, commercial compiler which supports more than 90 architectures, from 16-bit MSDOS to IBM mainframe; there is also an interpreter, free for personal use, and so well implemented that on my EVAL test it is second only to in assembly language written Picolisp, so OpenLisp can be attractive to those who like both lexical scope and dynamic scope and eval. Support is excellent. Check it. It definitely deserves more attention.