Here are a few samples to give you a feel for the Fexl language. You can also see the full grammar here.

say "Hello world."

The say function prints its argument followed by a line break (newline). The example above is equivalent to:

put "Hello world." nl

\x=(+ 3 4) \y=(* x x) say ["x = " x " and y = " y]

The say function also accepts an arbitrarily nested list instead of just an ordinary string. So that example would print:

x = 7 and y = 49

\hello=(later; say "Hello world.") hello hello

The output is:

Hello world. Hello world.

\show= (\x \y=(* x x) say ["x is " x " and x squared is " y] ) show (+ 3 4) show 5

The output is:

x is 7 and x squared is 49 x is 5 and x squared is 25

say "Type some stuff and press Enter:" beep beep # beep the speaker twice say ["You typed: " getline]

That example uses a couple of functions beep and getline which are not actually predefined in Fexl. However, it is possible to define any new external functions you need.

I like to think of Fexl as the "Plan 9" of programming languages, because you can establish any context you want for a given program text.

Start with a delimiter consisting of a ~ followed by zero or more non white- space characters, then a white space character to end the delimiter. That white space character is ignored. Then follow with the string itself, then a repeat occurrence of the delimiter.

say ~ "Ain't nothin' simple when you're doin' it for real." (Gus Baird)~ say ~EOM using a longer delimiter here~EOM

The newline after the terminator (~) is the white space that ends the terminator. It's not part of the string itself. In other words, the following string actually starts with the letter 'M'.

put ~ My fathers sleep on the sunrise plains, And each one sleeps alone. Their trails may dim to the grass and rains, For I choose to make my own. I lay proud claim to their blood and name, But I lean on no dead kin; My name is mine, for the praise or scorn, And the world began when I was born And the world is mine to win. ... (Badger Clark, "The Westerner") ~

\T = (\T\F T) \F = (\T\F F)

T is the function that chooses the first of two arguments; F is the function that chooses the second. Incidentally, this is built into the standard environment so you don't have to do it yourself, but it's interesting to see how it's done.

Fexl currently has built-in functions for manipulating numbers, strings, lists, mutable variables, and files. This can be easily extended by writing new combinators in C.

The append function appends two lists xs and ys. We define it with @ (the fixpoint operator) because it's recursive (calls itself).

The simplest definition is:

\append= (@\append\xs\ys xs ys \x\xs [x;append xs ys] )

However, Fexl does optimize that by (1) avoiding passing in the constant list ys to each iteration, and (2) by avoiding any repeated evaluation of list tails if you examine the result multiple times.

\append= (\xs\ys (@\loop\xs xs ys \x\xs \tail=(once; loop xs) [x;tail] ) xs )

\fib=(@\fib\x\y \z=(+ x y) [x; fib y z]) \fib=(fib 1 1) # Now "fib" refers to the entire infinite list of Fibonacci numbers.

The reverse function reverses a list. It uses an auxiliary function push_all which takes the list along with a stack which is initially null. That function pushes each element of the list onto the stack, returning the final value of stack as the reversed list.

# Push all entries in list xs onto list ys. \push_all=(@\loop\xs\ys xs ys \x\xs loop xs [x;ys]) # Reverse list xs. \reverse=(\xs push_all xs [])

# (filter f xs) is the list of items x in xs for which (f x) is true. \filter= (\f @\loop \xs xs [] \x\xs f x (cons x) (); loop xs ) # (sort xs) is the ordered list of all elements in list xs. \sort= (@\sort\xs xs [] \x\xs append (sort; filter (gt x) xs); # all the items less than x cons x; append (filter (eq x) xs); # all the items equal to x sort; filter (lt x) xs # all the items greater than x )

Here we represent natural numbers in binary notation, as a list of bits (T or F). The list [] represents 0, and the list [b;n] represents (b+2*n), where b is a bit and n is a natural number.

This is a highly advanced function, so don't expect to understand it at first glance, but it is interesting that it can be done in so few lines of code. It's surprisingly fast given that it's doing everything as pure lambda expressions. Of course, for heavy-duty arithmetic operations you'll probably want to use a built-in Big Number library.

# NOTE: div uses this function, defined elsewhere: # # (sub x y no yes) computes x minus y, returning: # yes d # if x >= y, with d = x - y # no # if x < y # (div x y) divides x by y, returning the quotient q and remainder r which # satisfy: x = q*y + r and 0 <= r < y. Or if y=0, the function returns q=0 and # r=0. \div= (@\div\x\y x {[] []} \bx\nx y {[] []} \by\ny by ( # divide by odd div nx y \q\r \r=[bx;r] sub r y (\d {[T;q] d}) {[F;q] r} ) ( # divide by even div nx ny \q\r {q [bx;r]} ) )

*2014-03-23*