Not Only Clojure — Shen Modern Lisp on Steroids

Volodymyr Pavlyshyn
5 min readSep 14

--

LISP — self-aware programs?

Lisp was designed to solve complex challenges in AI. Some of the features of LISP make it unique — self-reflection, symbolic programming, and the ability to operate with code as data opens an entirely new page in a metaprogramming.

Why should I care as a programmer?

Learning about Lisp will make you a better programmer. You can pick any language below based on the language you are familiar with to get you started with the lisp syntax more easily. It is also worth reading a post to get intuition for lisp syntax.

In general, learning any new programming language opens new horizons and improves programming insight. Modern programming languages are converging and sometimes are very similar to each other. The similarities can be missed because they are hidden behind a specific syntax.

If we translate the languages to a standard syntax, the similarities are more apparent, and the different concepts stand out more. That way we can focus on the new innovative concepts and ideas to broaden our horizons.

Clojure

The most popular lisp programming language today is JVM based clojure. It is widely adopted and used in production with some cool products built on top of it like Datomic and so on. ClojureScript deserves a separate article; it has dramatically changed on the frontend side. Clojure Universe deserves a different series of articles.

Not only Clojure

I want to show you a few nonclojure lisps that shift paradigms and ways of programming.

Exploring Shen

https://shenlanguage.org/ Shen is a functional programming language that brings a fresh perspective to the Lisp family. Created by Mark Tarver, Shen aims to be a versatile, efficient, and portable language suitable for various applications. In this article, we’ll explore the key features that make Shen stand out, complete with code examples to illustrate each feature.

Strong Type System

Shen’s type system is one of its most powerful features. Unlike many other dynamic languages, Shen allows for optional type annotations that can catch errors at compile-time, making the code more robust.

(declare factorial : number --> number)

OPTIONAL TYPE CHECKING

(tc +)
(define map
{(A --> B) --> (list A) --> (list B)}
_ [] -> []
F [X | Xs] -> [(F X) | (map F Xs)])
(map (+ 1) ["a" "b" "c"])> type error

CONFIGURABLE TYPE RULES

(datatype maybe-type
  _____________________
none : (maybe A);
X : A;
_____________________
(some X) : (maybe A);
M : (maybe A);
_____________________
(unwrap M) : A;)

Pattern Matching

Pattern matching in Shen allows you to destructure data and execute code based on its shape. This feature enhances code readability and expressiveness.

(define filter
_ [] -> []
F [X | Xs] -> [X | (filter F Xs)] where (F X)
F [_ | Xs] -> (filter F Xs))
(define element?
_ [] -> false
X [X | _] -> true
X [_ | Y] -> (element? X Y))

Streams and Lazy Evaluation

Shen supports lazy evaluation, which is particularly useful for handling large data sets or streams of data.

(define stream-map
F [] -> []
F [H | T] -> [(F H) | (stream-map F T)])
(let F (freeze (output "Hello!"))
(thaw F))

Concurrency

While not built into the core language, Shen has libraries that support concurrency, making it suitable for multi-threaded applications.

(async (lambda () (print "Hello from another thread!")))

First-Class Continuations

Shen supports first-class continuations, allowing for advanced control flow mechanisms like coroutines and backtracking.

(define call/cc
F -> (F (lambda X (throw X))))

Tail-Call Optimization

Shen performs tail-call optimization, making recursion as efficient as iteration.

(define factorial-tail-rec
N Acc -> (if (= N 0) Acc (factorial-tail-rec (- N 1) (* N Acc))))

Metaprogramming

Shen excels at metaprogramming, allowing you to write code that writes or modifies other code.

(define-macro defun-square
[Name X] -> `(define ,Name ,X -> (* ,X ,X)))

Macros

Macros in Shen let you extend the language by defining new syntactic constructs, offering a powerful way to create domain-specific languages or optimize code patterns.

(defmacro infix-macro
[X + Y] -> [+ X Y]
[X * Y] -> [* X Y])

Built-in compiler compiler

The built-in compiler-compiler enables you to create new language constructs or even whole new languages. It’s a powerful feature for those who want to extend the language or build domain-specific languages, offering a level of flexibility that’s rare in most programming languages.

(define bit?
B -> (element? B [0 1]))
(defcc <b>
B <b> := [B | <b>] where (bit? B);
B := [B] where (bit? B);)

Despite macros it is allow you to create a new syntax and mini languages

Interactive Development (REPL)

Shen supports a Read-Eval-Print Loop (REPL) for interactive development, which can be initiated by running shen in your terminal.

Exception Handling

Shen provides a robust exception-handling mechanism, allowing you to catch and handle errors gracefully.

(trap-error (do-something-risky) (lambda E (print "An error occurred")))

Foreign Function Interface (FFI)

Shen can interface with code written in other languages, making it easier to integrate with existing systems or libraries.

Built-in Testing Framework

Shen comes with a built-in testing framework, making it easier to write and run tests for your code.

(test (+ 1 1) => 2)

Formal Verification

One of the unique features of Shen is its ability to perform formal verification of code, thanks to its powerful type system and sequent calculus.

(declare factorial : number --> number)

Logic Programming

Shen incorporates elements of logic programming, similar to languages like Prolog. This makes it suitable for tasks like AI, rule-based systems, and database queries.

(define prolog-member
X [X | _] -> true
X [_ | T] -> (prolog-member X T)
_ [] -> false)

Backtracking

backtracking can be implemented using first-class continuations. These continuations capture the current state of a computation and allow you to return to it later, effectively enabling you to explore multiple paths in an algorithm. When a dead-end is reached, you can “rewind” to a previous state using the captured continuation, thereby implementing backtracking. This is particularly useful in algorithms that require exploring multiple solutions, such as puzzle-solving or optimization tasks.

(define walk
_ [] <- (fail)
F [X | _] -> X where (F X)
F [_ | Y] -> (walk F Y))

Portability

Shen is ported to many languages and environments.

Shen for JavaScript

https://github.com/rkoeninger/ShenScript

  • Allows integration with arbitrary I/O.
  • Async operations are transparent to written Shen code.
  • Easy interop: JS can be called from Shen, Shen can be called from JS.
  • Relatively small production webpack bundle (~370KB uncompressed, ~60KB gzip compressed).
  • Decent web startup time (~50ms in Chromium, ~100ms in Firefox).

Conclusion

Shen is a modern Lisp variant that offers a unique blend of functional and logic programming features. Its strong type system, pattern matching, and metaprogramming capabilities make it a versatile choice for various kinds of projects. Whether you’re interested in data processing, AI, or system programming, Shen has something to offer. You could watch a talk

--

--

Volodymyr Pavlyshyn

I believe in SSI, web5 web3 and democratized open data.I make all magic happens! dream & make ideas real, read poetry, write code, cook, do mate, and love.