4 ms·
So, how is this different/better than other functional languages?
by gmartres 15y ago
So, how is this different/better than other functional languages?
- fexl 15y agoOK, I'll discuss what's different and leave "better" out of it. 1. In Fexl, there is no distinction between data and function. All data structures such as lists, pairs, etc. are represented as functions. 2. Fexl has a small grammar, about as small as I think is feasible for expressing arbitrary functions. You could actually omit these rules: exp => \ sym = term exp exp => \ sym == term exp exp => ; exp But the resulting forms would be far more difficult to write and understand. 3. Fexl has a very simple compilation and evaluation strategy, reducing everything to combinatorial forms. There are no "environments" or "closures" or "contexts" being whipped around at run-time. The resulting Fexl executable program is about 35K in size. 4. Unlike other functional programming languages, Fexl does not rely on "pattern matching" for branching on the different possible forms of a piece of data. Instead, it simply calls that piece of data as a function, passing in the appropriate handlers for the various cases. For example, using excessively verbose function names here: list handle_empty_list \head\tail handle_first_item head; handle_remainder tail 5. Fexl doesn't really have a distinct concept for defining a name -- that's all handled normally by lambda calculus. However it does provide the syntactic shorthand "=". For example this function: \square = (\x mul x x) print (square 4) Is equivalent to this function, which does not use the "=": (\square print (square 4)) (\x mul x x) I'm not exactly sure if that's oh-so-different from other programming languages, but I'll venture a guess that many of those other languages use a symbol table to store function definitions at run-time, while Fexl does not. 6. Fexl never creates circular data structures in memory. Now because of lazy evaluation, you can create logically circular or infinite structures in Fexl, but these are always closed forms and never involve literal circularity in memory. Consequently it is possible to manage memory using reference counting -- and Fexl does that. Some may not like that, but it's simple and it gets the job done. The code even has a built-in assertion to ensure that all memory was properly reclaimed at the end of a run. (I'm not certain that other languages create circular structures in memory, but I am certain that Fexl does not so I thought it worth mentioning.)
- gmartres 15y agoThat's interesting, but excluding the "reducing to combinatorial forms" thing, which only seems to be an implementation detail, can't this all be done in Scheme or another Lisp dialect? "no distinction between data and function" goes hand in hand with https://secure.wikimedia.org/wikipedia/en/wiki/Homoiconicity https://secure.wikimedia.org/wikipedia/en/wiki/Homoiconicity
- fexl 15y agoYou can certainly do this sort of thing in Lisp, using forms like: (defun square (x) ...) (lambda (x y) ...) (add 2 (add 3 (add 4 5))) In Fexl you would see instead: \square = (\x ...) \x\y ... add 2; add 3; add 4 5 So at least Fexl has the virtue of being more compact in those cases. :) Also, in Fexl, whenever you see a name, it always refers to a function, unlike in Lisp, where names like "defun" and "lambda" and "prog" are meta-logical syntactic devices and cannot be defined as functions in their own right. And anything like "setq" or "setf" is strictly out of the question in Fexl. You could of course implement lazy techniques in Lisp, even going so far as to write a Fexl interpreter if you like. I just wanted to see what happened if procedural, mutable, and meta-logical constructs were completely eliminated as possibilities in a language.
- gmartres 15y agoSo, Haskell without types and monads basically? ;)
- fexl 15y agoDefinitely without the types, yes. However, monads are completely do-able in Fexl. I can write Fexl code that looks procedural and "side-effect-y", using the monadic technique so that you never actually see the state variable that's being chained through the functions. Monads are more a style of code than a feature of the language per se. Personally I'm quite happy without the baggage of type declarations. As long as I build up functions systematically, I have very few problems with run-type type violations. Sure every once in a while I forget a semicolon or whatever and my function gets "out of synch" like a T-1 line gone out of phase. But it's usually pretty easy to see what went wrong.