this is another entry in a series on programmer enrichment
A language that doesn’t affect the way you think about programming is not worth knowing. – Alan Perlis
inspired by a LtU thread and the great post Programming Achievements: How to Level Up as a Developer by Jason Rudolph[^my-list]. most code samples from Rosetta Code.
The philosopher Friedrich Nietzsche believed that all interactions and interpretations of the external world occurred through the lens of individual perspective. Therefore, truth to Nietzsche was subject to interpretation. Programmers are especially prone to subjective views on their industry best-practices and valuations, often colored by their chosen[^chosen] programming languages.[^not-just] However, Nietzsche believed that in order to achieve a high-level of thinking, one should grant all perspectives equal opportunity and let them stand, or fall, on their own merits. You’ve probably experienced this approach yourself in college if a professor demanded the classic assignment whereby students write an essay taking the side of an argument that they themselves denounce. This type of exercise is potentially very powerful in that it often works to crystalize one’s own beliefs and occasionally helps to shake those beliefs to the core.
A Perlis Language is a programming language that I believe will shake one’s views on software development to the core.
Below I will enumerate[^npo] some of my Perlis Languages and give an all-too-brief overview and just a sip of code for each.
Joy is an example of a concatenative programming language or more simply put, a stack-based language. That is, functions are never explicitly passed arguments, but instead take an implicit stack that is maintained by the programmer. This may seem totally insane, a sentiment not wholly inaccurate, but the levels of succinctness and elegance achieved via this model is stunning. The complexity in maintaining a stack is typically handled by concatenative programmers through the process of vigorous factoring of words (think functions) into smaller words. There is a whole class of purely stack-manipulation primitives that signal the need for factoring when their use becomes too pervasive. The goal is to constantly drive the code toward an expression of the domain rather than an expression of the programming language-specific expression of the domain. There are certainly better and more historically significant concatenative languages, but Joy strikes a nice chord with me – your mileage may vary.
(* Quicksort in Joy *)
DEFINE qsort ==
[small]
[]
[uncons [>] split]
[swapd cons concat]
binrec .
Daniel Spiewak wrote a great trilogy about concatenative languages; his treatment is far better than I could ever produce.
possible substitutes: Factor, Forth, Cat, PostScript
Eiffel is an extremely opinionated object-oriented programming language. Like myself, many programmers today have a majority-share of “real-world” experience in one OO language or another. However, you haven’t used anything like Eiffel. That is, the bulk of Eiffel will be recognizable to most programmers, but the enlightening feature for most is the first-class support for Design by Contract. In a nutshell, DbC (or contracts programming) is an approach that allows one to specify the expectations on method results based on their required input parameters and also to define class-level invariants.[^inv] This may seem fairly simplistic, but it’s in this simplicity that forms the basis for an extremely powerful design paradigm. In fact, contract support libraries and extensions have been created for other languages: Ruby, Clojure, C++, Java, and Groovy to name only a few.
-- Dictionary class fragment
class DICTIONARY [ELEMENT]
feature
put (x: ELEMENT; key: STRING) is
-- Insert x so that it will be retrievable
-- through key.
require
count <= capacity
not key.empty
ensure
has (x)
item (key) = x
count = old count + 1
end
invariant
0 <= count
count <= capacity
end
possible substitutes: D, Cobra
Qi is a Lisp – big deal right? Wrong. Qi is a Lisp with skinnable types, a built-in logic engine, rewrite rules, back-tracking dispatch, built-in lexer and parser generators, and pattern matching that compiles down to highly-performant Common Lisp. The author Dr. Mark Tarver has strong opinions on the state of the software development in general and Lisp in particular (you may already have read The Bipolar Lisp Programmer) and these opinions shine in the implementation of Qi. The successor to Qi, Shen, is in active development with a release scheduled some time this summer.
\ A simple expression calculator \
(datatype arith-expr
X : number;
====================
[num X] : arith-expr;
if (element? Op [+ - * /])
X : arith-expr; Y : arith-expr;
===============================
[X Op Y] : arith-expr;)
(define do-calculation
{arith-expr --> number}
[X + Y] -> (+ (do-calculation X) (do-calculation Y))
[X - Y] -> (- (do-calculation X) (do-calculation Y))
[X * Y] -> (* (do-calculation X) (do-calculation Y))
[X / Y] -> (/ (do-calculation X) (do-calculation Y))
[num X] -> X)
possible substitutes: Pure
Clojure is a fantastic language, but let’s just say that I have some skin in this game. Take this entry with a grain of salt. So instead…
Kernel is also a Lisp, but it differs in that it completely eliminates the line separating compile-time and runtime via [fexprs