Here I illustrate how to use simple nested associative arrays to track complex state.
This is a follow-on to the discussion In Lisp, should lists be replaced with trees? I aim to do more and more of my production code in Fexl if possible. The hedge fund accounting software I wrote in Perl is quite complex, managing a large amount of intricate state. I chose to represent all that state as a completely flat key-value store in memory, where I write out the keys that changed at the end of each batch.
Naturally that approach seems at odds with a purely functional language such as Fexl, but I'm trying to overcome that apparent mismatch simply by buckling down and doing the key-value logic in Fexl.
There are some fans of Fexl out there, myself included, who are not yet completely clear on how to use it for production code. The jury's still out. I hope that samples like this will help.
The example uses nested associative arrays (maps) to track complex state. You'll notice that I do not use the "monadic" style to make the maps implicit. I just manage the map states explicitly. By the way, I use functions "item" and "end" as my two list constructors, instead of the traditional "cons" and "null". That's just my stylistic preference.
(NOTE: the following code uses plain linear associations lists. For large key sets this can get slow, so you might want to use nested association lists instead for better performance.)
# Basic assoc list operations get and put. (I'll do del in a bit.)
\get == (\map\key\default
map
default
\head\tail head \top_key\top_val
string_compare key top_key
default
top_val
(get tail key default)
)
\put == (\map\key\val
map
(item (pair key val) end)
\head\tail head \top_key\top_val
string_compare key top_key
(item (pair key val) map)
(item (pair key val) tail)
(item head; put tail key val)
)
# The put_qty and get_qty routines use nested assoc lists to track the qty of
# each symbol.
\put_qty = (\map\sym\qty
\map_qty = (get map "qty" end)
\map_qty = (put map_qty sym qty)
put map "qty" map_qty
)
\get_qty = (\map\sym
\map_qty = (get map "qty" end)
\qty = (get map_qty sym 0.0)
qty
)
# Add a quantity to the existing quantity of a symbol.
\add_qty = (\map\sym\qty
\old_qty = (get_qty map sym)
put_qty map sym (add qty old_qty)
)
# Some test print routines.
\test_val = (\map\key
\val = (get map key "")
print "key ";print key; print " val ";print val;nl;
)
\test_qty = (\map\sym
\qty = (get_qty map sym)
print "The quantity of ";print sym;print " is ";print qty;nl;
)
# Now build up some data and print some tests.
\map = end
\map = (put map "banana" 4.9)
\map = (put map "apple" 3.8)
\map = (put map "mango" 5.7)
test_val map "apple";
test_val map "mango";
test_val map "applex";
test_val map "banana";
\map = (add_qty map "IBM" 33.0)
test_qty map "IBM";
\map = (add_qty map "IBM" -5.0)
test_qty map "IBM";
test_qty map "XYZ";
The output of that function is:
key apple val 3.8 key mango val 5.7 key applex val key banana val 4.9 The quantity of IBM is 33 The quantity of IBM is 28 The quantity of XYZ is 0