Show all entries

Mon 2022-02-21

Some notes on Fexl

Today I posted this comment to a Magmide discussion list. Here's what I wrote.

You might want to check out some of the concepts in my functional programming language Fexl. I have been using it almost exclusively for years in my business, which is accounting for investment partnerships.

Fexl is not statically typed. I figured if I wanted to build a static type system, I would do that in Fexl itself, which would start off untyped. So far I have not been inclined to do static typing. Good systematic development with regression testing and full coverage have worked very well for me. Personally, I find statically typed languages to be too burdened with cumbersome declarations.

Although Fexl is not "purely functional," you can make any program be exactly as "pure" as you want it to be. For example, I/O is straightforward, so the "Hello, world" program is simply; say "Hello, world." There is no "monad" there, just a call to the "say" routine. To make that program purely functional, you would write a function that returned the string "Hello, world." Then a higher-level "impure" layer would be tasked with applying "say" to that result.

If you want to do "memoized" functions, Fexl has routines for doing mutable variables. This can be nice for optimizing naive versions of recursive functions like Fibonacci, or the Partition count function which is far more self-recursive. (Note: I'm personally in favor of a more purely functional approach to memoization, where an immutable cache table is explicitly passed around in and out of the function, but sometimes the grungy mutable approach will save you in a pinch.)

Fexl represents recursion explicitly using the fixpoint operator, which I denote by "@". The nice thing about explicit fixpoint recursion is that a call to a recursive function can be expanded directly in place -- i.e. referential transparency applies here as well. You can also identify some interesting optimizations where some parameters are fixed and do not need to be passed into recursive calls. (Note: Tail recursion "just works" because of how I do parameter substitution. I don't have to do anything special to get it.)

Fexl also has a very useful feature for idempotent "once" calculations. If you have an expression such as (f x y) buried somewhere, and maybe it takes a long time to run or even has side effects you only want to happen once, you can change the expression to (\= f x y) and then it only runs once, if you happen to call it. I cannot emphasize enough how useful and convenient that is for my real project work.

My design goal for Fexl was to have a language which is as close to pure lambda expressions as possible, with additional syntax added only to make it practical. Most of the additional syntax has an equivalent plain lambda expression. Another goal was to implement Fexl in the smallest feasible plain C code, which I think I've done.

I'll leave it there for now. If you'd like me to elaborate anything further, please let me know. You may find some of the ideas helpful in your efforts. For example, I think I've done very solid work on concepts such as parameter substitution, and the closely related concept of modularity, which Fexl handles using functions known as "contexts."