
\documentclass[12pt]{article}
\usepackage[T2A,OT1]{fontenc}
\usepackage[default]{cantarell}
\usepackage[a4paper, top=20mm, bottom=20mm, left=20mm, right=20mm]{geometry}
\usepackage[utf8]{inputenc}
\usepackage[russian, english]{babel}
\usepackage{tabu}
\usepackage{hyperref}
\usepackage{parskip}
\usepackage{graphicx}
\usepackage{tabularx}
\usepackage{float}
\floatstyle{boxed}
\restylefloat{figure}
\usepackage{setspace}
\onehalfspacing
\author{Artyom Bologov}
\date{\today}
\title{Parameterized Procedures for Testing, Mocking, Plumbing}
\makeatletter
\def\endenv{\expandafter\end\expandafter{\@currenvir}}
\makeatother
\begin{document}
\maketitle

\includegraphics[width=\textwidth,height=\textheight,keepaspectratio]{./assets/parameterized.png}

I'm about to suggest a simple solution to the problem of

\begin{itemize}\item Mocking a procedure for testing.
\item  Inserting pre-computed results into computation.
\item  Temporarily overriding a procedure.
\end{itemize}

From this list, it's more or less evident why one might need this.
But I'll explain my context anyway:

\section*{The Problem} \label{problem}

Biological computations are fun:

\begin{itemize}\item They are hard to read on paper.
\item They are even harder to read in code.
\item And they take an awful lot of resources to compute.
\end{itemize}

So I ran one computation piece that took several hours.
It wasn't nice waiting for so long.
(Even though I got some delicious cherry ice cream while waiting for it.)
I've sworn to optimize it, or otherwise make it bearable to debug.

There was this one function, \verb|mph-em|, that was taking most of the time.
Especially so on first run.
It was an important one and there were no corners to cut.
I tried:

\begin{itemize}\item Memoization/caching.
\item  Micro-optimizations.
\item  Rewriting parts of it in C.
\end{itemize}

It wasn't enough.
I needed to somehow avoid the long-running computation altogether.
And just get the result.
I needed to pre-compute the results of \verb|mph-em| and plug them into the program.
But what if it's too deep into the program and I can't feasibly pass anything from outside?

\section*{The Solution: Parameterize} \label{solution}

Lisps have a long tradition of dynamic vs. lexical binding wars.
Lexical bindings won, but there are uses for dynamic bindings.
Like temporary procedure/value overriding!
So I reached for Scheme's take on dynamic bindings,
\href{https://srfi.schemers.org/srfi-39/}{SRFI-39 Parameter objects}
and came up with this macro:
\begin{figure}[h!]\begin{verbatim}
;; Define a NAMEd procedure and PARAMETER-NAMEd parameter
;; variable. Proceeds with running BODY with ARGS when PARAMETER-NAMEd
;; variable is #false. When PARAMETER-NAME is `parameterize'd to a new
;; procedure, call this procedure on ARGS instead. Useful to override
;; a procedure (like replacing the results for testing or providing
;; shortcut data for long-running computation.)
(define-syntax define-parameterized
  (syntax-rules ()
    ((_ ((name parameter-name) . args) body ...)
     (begin
       (define parameter-name (make-parameter #f))
       (define (name . rest)
         (apply (or (parameter-name)
                    (lambda args body ...))
                rest))))
    ((_ (name . args) body ...)
     (define (name . args) body ...))
    ((_ name value)
     (define name (make-parameter value)))))
\end{verbatim}\caption{define-parameterized macro allowing to easily override a procedure/variable temporarily}\end{figure}

So now I can \verb|define-parameterized| my \verb|mph-em| and plug (via \verb|parameterize|) it in whenever I need it:
\begin{figure}[h!]\begin{verbatim}
(define-parameterized ((mph-em %mph-em) reml? eval x y vg ve b)
  #|...|#)
(parameterize ((%mph-em (lambda args (mtx:alloc #(#|...|#)))))
  (code-calling-mph-em))
;; Or, if you only need it to fire once
(parameterize ((%mph-em (lambda args
                          (%mph-em #f)
                          (mtx:alloc #(#|...|#)))))
  (code-calling-mph-em))
\end{verbatim}\caption{Use of define-parameterized}\end{figure}

I was unsure whether this post should've been written altogether.
It's quite obvious, right?
But it might be just my knowledge bias, so here goes nothing!
Tell me whether it's obvious or not, in the feedback form below ↓

And hey, give this macro a go!
SRFI 39 is the only dependency and
\href{https://practical-scheme.net/wiliki/schemexref.cgi?SRFI-39}{is pretty well supported},
so no trouble in trying!

\par\noindent\rule{\textwidth}{0.4pt}
Copyright 2022-2025 Artyom Bologov (aartaka).
Any and all opinions listed here are my own and not representative of my employers; future, past and present.

\end{document}
