Skip to content

Instantly share code, notes, and snippets.

@sroccaserra
Last active November 30, 2020 12:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sroccaserra/528fda139421a289f7305f1b10494932 to your computer and use it in GitHub Desktop.
Save sroccaserra/528fda139421a289f7305f1b10494932 to your computer and use it in GitHub Desktop.
Lisp constraints: 100 % s-expressions => recursion +"code is data" => expressivity

Introduction

Fast Backward!

Lisp is worth learning for the profound enlightenment experience you will have when you finally get it; that experience will make you a better programmer for the rest of your days, even if you never actually use Lisp itself a lot. – http://www.paulgraham.com/avg.html

So let's code like it's 1963, and explore the modernity and expressive power that the symbolic expression (s-expression) constraint offers!

To do that, let's try to extend the language expressivity by defining a pipe macro that, by rearranging the s-expressions given in input, allows us to write:

(pipe x
      (+ 6)
      (sqrt)
      (number-to-string))

instead of:

(number-to-string (sqrt (+ 6 x)))

Time to code

Note to self: open Emacs, and code & explain the kata. See file below to read an implementation example.

Note to self: C-x C-+ to enlarge font (or C-M-= and C-M-- with default-text-scale).

Discussion

Today, we can get pretty close to this expressivity in languages like JS with syntaxic sugar for lambdas & Python with operator metaprogramming, or even better in curry-by-default ML-type languages (Haskell &all).

JavaScript:

_.flow(x => 6 + x,
       x => Math.sqrt(x),
       x => console.log(x))(5);

Haskell:

Data.Function> 3 & succ & recip & negate
-0.25

But starting in 1959, Lisp was already closer to today's standards in expressivity than to the other languages of its time that I know of (think FORTRAN, COBOL).

Conclusion / takeaway

Strong & well chosen constraints can sometimes yield strong leverage.

Some old languages still have gems & lessons that we can still benefit & learn from even today.

Other inspiring languages with strong constraints that I know of:

  • Forth (1968)
    • Stack based
    • => Portable, small & efficient, easy to extend & maintain
  • Smalltalk (1972)
    • 100 % objects & messages only
    • => Easy syntax, very low code complexity, modern realtime debugging tools
  • SQL (1974)
    • Strong structure based on the relational model
    • => Easy to make cross products & data projections
  • Erlang (1986)
    • 100 % message passing, share-nothing between processes
    • => Easier to write fault tolerant distributed systems
  • Haskell (1990)
    • Pure mathematical functions, no mutations, curry by default
    • => Super easy to compose functions, really expressive type system
;;;
;; Code
(defmacro pipe (x &optional form &rest more)
(cond
((null form) x)
((null more) `(,@form ,x))
(:else `(pipe (pipe ,x ,form) ,@more))))
;;;
;; Tests
(require 'ert)
(ert-delete-all-tests)
(ert-deftest pipe-function ()
(should (equal (macroexpand '(pipe x))
'x))
(should (equal (macroexpand '(pipe x
(- 6)))
'(- 6 x)))
(should (equal (macroexpand '(pipe x
(- 5)))
'(- 5 x)))
(should (equal (pipe 5
(- 6))
1))
(should (equal (macroexpand-all '(pipe x
(- 6)
(* 9)))
'(* 9 (- 6 x))))
(should (equal (pipe 5
(- 6)
(* 9)
(number-to-string))
"9")))
(ert t) ;; M-x eval-buffer
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment