Clojure on the M1: notes and a quick comparison
The original post from 2020 is HERE
The original post from 2020 is HERE
As an experiment in concise function naming, consider using the classic Lisp (x->y) ‘coercion/conversion’ syntax as much as possible in your Clojure code. What are some consequences of programming in this manner?
First note that a slightly gratuitous semantic cast of the ‘coercion/conversion’ endpoints is probably required. By referring to these endpoints as ‘entities’ you accrue a bunch of functions where entity->entity and program logic is then dominated by entity transformations.
Entity oriented Naming.
In statically typed languages such as OCaml/Haskell/Rust/etc you have both a function name and a function signature.
We need the function names because some things are different from other things, and because type signatures describe ingress and egress things but not necessarily what happens inside the function.
For example the function:
bank-balance
might have a type signature of:
id->double
but then so might a much nicer function:
bottomless-bank-balance
id->double
More seriously, it would be nice to have concise function names that are both structurally and semantically descriptive.
as Clojure is dynamically typed these are treated as type-like rather than actual types (although some entities are actually types, e.g., String) and any associated discipline is handled manually
the names of functions consist of only one or two entity clauses, representing input and output
parameters may not be apparent from the name, but you can easily read the endpoints. Actual function parameters are only an IDE convenience feature away
function names may resemble function signatures but the name clauses do not necessarily represent function parameters, and entity-endpoint name clauses do not imply currying
entities are value-like but not necessarily pure or referentially transparent
they blend well with pre/post block asserts
they encourage names like location-value over something like get-location-value
and entities & functions mostly sort into the expected lisp-ish categories:
Some examples from an application written in this manner
nouns:
packed-codon
upacked-codons (list)
image-file
MResult
string
out
verbs:
text-file->image-file
image-file->string
packed-message-string->MResult
state mutator / destructive:
draw-image-pixel!
predicates:
supported-image-file?
fasta-file?
verb-likes/actions
cli-decode
cli-encode
and some example code
(defn otp-image-file->string
"Given OTP-encoded image file + appropriate key files,
return plaintext.
note: By app convention, filenames are used as
file references."
[fname, key-files]
(packed-codon-string->string
(apply str
(map codon->packed-codon
(string->unpacked-codons
(packed-codon-string->string
(image-file->codon-string-themed fname))
string->otp-numcodes
key-files )) )) )
(defn image-file->string
"Extract the base-encoded text from an AGCTAG-style image"
[fname]
(->> fname
image-file->codon-string-themed
packed-codon-string->string ) )
pros:
cons:
mehs:
Ok sure, yet another facile remix of some Lisp-isms. But consider:
These conventions emphasize the ‘verb’ aspect of functions. Construction tends to proceed verb-first, then with the identification of noun-like abstractions.
In practice, cases where entities do not arity-map to function parameters are not really as confusing as might be initially assumed and can help reveal overly complex function signatures. And if there is an implicit pressure towards reducing the number of function parameters, this is probably not a bad thing.
The data transformation style of programming emphasized by this naming scheme seems to fit well with Clojure, and the type-like names do seem to facilitate function reuse.
Using this structural pattern you quickly accrue a lexicon of the entities. This can be a nice addition to your documentation, even if you use a doc generator.
And finally, it’s not unusual for vaguely-named or “processor/handler” functions to tend toward bloat accretion. An entity->entity naming style can help keep such naughtiness in check.
I have found that this fairly simple style of nomenclature can both improve program readability and facilitate logic organization. Perhaps you will find it helpful as well.