Matrico utils Module
matrico
’s Utilities Module utils
utils
is the base module of the matrico
project and imported by every other module.
It contains a collection of miscellaneous bindings, macros and functions for general use.
You can take a look at the src/utils.scm
source file here.
Meta Helpers
Scheme’s macro system is insanely powerful.
However, I often only need a handful of macro helpers.
First, the generic define-syntax
is to bulky if you only have a single rule;
for this, I use a macro that makes the syntax definition look like a function definition, inspired by Guile.
Also, I require a shortcut for asserting a variable argument list of tests, typically to check argument types and properties.
There are two reason for not using a function here: asserts are removed by the CHICKEN compiler in “unsafe”-mode, so this might litter,
and, I am using and
which I cannot pass into apply
since it is a special form.
Lastly, I was intruiged by Clojure’s rich comments, which were already part of the T language.
Altogether:
(define-syntax-rule )
- Wrapper for single rule macros.(must-be arg ...)
- Wrapper forassert
ofand
with variable number arguments.(comment ...)
- S-expression comment, all content is ignored and void is returned.
The comment
macro will not be found in the release code bases, I just use it during development.
List Aliases
I never warmed up to Lisps’ car
and cdr
function names, even given the
sometimes useful predefined compositions of car
s and cdr
s (See
car
and cdr
for more info).
I prefer StandardML’s “head” (hd
) and “tail” (tl
), and even if
not all cdrs are tails, every coin has a pair
of heads and tails.
Then, Lisp has nil
as a name for the empty list,
and I prefer three letters to three symbols typing-wise.
I note here, that in Lisp the empty list also is a boolean false value, while in Scheme only and only #f
is false. Finally, I find Racket’s
empty?
is much more readable then null?
. Thus the following names are bound:
nil
- Name for the empty list symbol'()
.(head lst)
- Alternate name forcar
returning first member of argument pair.(tail lst)
- Alternate name forcdr
returning second member of argument pair.(empty? lst)
- Alternate name fornull?
returning true if tail of argument pair is nil.
These are bindings and can’t use the alias
macro, otherwise they couldn’t be passed as functions.
Fixnum helpers
For performance and readability reasons I want to ensure and document that for indexing operations fixed-size integers and integer operations are used. CHICKEN has the matching (chicken fixnum) module for this purpose. However, I added a few currying macros, like increment and decrement as well as predicates comparing to zero:
(fx+1 x)
- Increment fixnum argument.(fx-1 x)
- Decrement fixnum argument.(fx=0? x)
- Returns true if fixnum argument is zero, false otherwise.(fx<0? x)
- Returns true if fixnum argument is less than zero, false otherwise.(fx>0? x)
- Returns true if fixnum argument is greater than zero, false otherwise.(fx<=0? x)
- Returns true if fixnum argument is less or equal to zero, false otherwise.(fx>=0? x)
- Returns true if fixnum argument is greater or equal to zero, false otherwise.
As integers are so fundamental for programming and it is hard to imagine using the above
fixnum helpers without other fixnum functions, I let the utils
module reexport
the (chicken fixnum)
module.
List Functions
Rarely, one needs to extract a part of list between two indices, similar to
the non-standard but prevalent subvector
for vectors. However, there is a specific
use for this un-schemy (due to the indexing of a list) function.
Furthermore, heuristically it turned out using folding via (foldr
) instead of
append
to append an element to a list is more memory efficient, thus a
fold-based append variant is supplied.
Unlike in SRFI-1, my any?
and
all?
(“all” instead of “every”) functions return boolean values, and thus have
question marks signifying a predicate. These leads to:
(append* lst any)
- Returns argument list appended with element argument.(sublist lst start end)
- Returns list partition of list argument inbetween the index arguments.(any? pred lst)
- Returns true if any element of list argument applied to function argument is true, false otherwise.(all? pred lst)
- Returns true if all elements of list argument applied to function argument are true, false otherwise.
Factorials
A classic example for recursive computation is the factorial. Here, it is implemented to be able to test another function from another module. Furthermore, the related binomial cofficient is provided where the implemented algorithm, Pascal’s rule, hints at its use.
(factorial n)
- Returns product of consecutive integers up to argument, starting at one.(binomial n k)
- Returns binomial coefficient for given integer arguments.
Note, that a computation of the binomial coefficient via its iterative definition (using the factorial) is very inefficient.
Standard Variants
Scheme, particularly CHICKEN Scheme, is awesome. Whatever you can imagine, be it docstrings (see also this) or a data-file loading, one can implement with a few lines of code:
(define* ...)
- Defines a binding together with a docstring for various forms ofdefine
.(load* pathstr)
- Loads and evaluates file a argument string path and returns the result of the last expression.
While define*
is a language extension via a pattern matching macro, load*
is wrapping load
,
whose return value is unspecified, a function using eval
.