Lisp certainly has many advantages, but general readability is not one of them. Maybe when talking about complex algorithms with a sufficiently designed DSL... Here's your code reformatted:
(defun memoize (fn)
(let ((cache (make-hash-table :test #'equal)))
#'(lambda (&rest args)
(multiple-value-bind (val win) (gethash args cache)
(if win val
(setf (gethash args cache) (apply fn args)))))))
And here is a prettier (use of TryGetValue), C# 3.0 (Func types, local variable type inference) version:
static Func<TParam, TReturn> Memoize<TParam, TReturn>(Func<TParam, TReturn> func)
{
var memoDict = new Dictionary<TParam, TReturn>();
return arg =>
{
TReturn result;
if (!memoDict.TryGetValue(arg, out result))
{
result = func(arg);
memoDict[arg] = result;
}
return result;
};
}
The C# version is clearly longer, but less dense. Most of the noise in the C# version comes from the verbose type declarations. Almost anyone could read the C# code, provided they know that => means lambda and at least heard of a closure. That is not true of the Common Lisp version. As with everything in engineering, it is a balance. Lisp is absurdly powerful and C# is absurdly clear to read. As a programmer who does
a lot of maintainence programming at work, I highly appreciate that attribute of the language.