5 ms·
Compare the C# version of memoize to this one (from On Lisp). The C# one looks very long and ugly in comparison, so I hope it isn't the new Common Lisp. (defun
by justinhj 17y ago
Compare the C# version of memoize to this one (from On Lisp). The C# one looks very long and ugly in comparison, so I hope it isn't the new Common Lisp.
(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)))))))
- snprbob86 17y agoLisp 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.
- lispm 17y agoI would format the function like this: (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))))))) I'm a Lisp programmer and the C# arglist is already hard to parse with lots of noise - for me. Second I don't look for { or ( but for the block indentation, so a { on a single line does not give me enough visual clues. The 'return arg =>' form is not obvious to me. What does it do? Where dies TReturn come from, TParam? Why is there }; and } ?
- snprbob86 17y ago=> denotes a lambda. The left side is the args, the right side is the body. Lambdas are typically a single expression, but can have a statement body instead. A semicolon denotes the end of a statement. var square = x => x * x; var square = x => { return x * x; };
- pyre 17y ago> Second I don't look for { or ( but for the block indentation, so a { on a single line does not give me enough visual clues. We could argue for days about these sort of issues, and there are passionate ideas on either side of the fence. function { code; code; } In that form, you have the beginning { and ending } for explicitly define the beginning and ending of the code block, and all of the code inside is also indented for good measure. Maybe it's redundant, but I don't see how it's wildly different from: function code; code; > Why is there }; and } ? Have you never programmer outside of lisp? I've never programmed in C#, but if 'arg =>' is the beginning of lambda, then it's because the definition of that line is return EXPRESSION;. And in that case EXPRESSION = 'arg => { code }'. That's where the ';' comes from.
- stefano 17y agoI don't know C#, but it seems to me that your C# version of memoize works only for functions with exactly one argument, while the CL version works for any kind of function.
- snprbob86 17y agoYeaaah.... It turns out that generic methods with variable arity is a sore spot for the .NET type system. The C# and F# teams are quite aware. The typical/recommended/easy/practical solution is to just provide another overload, pack the args into an object array, and then call the original overload; completely ignoring the problem. Alternatively, you could do some scary things with reflection...
- justinhj 17y agoHmmm, I guess I should learn how to format text on hn when I want to make a point about readability. ;-) Even so, with the caveat that you have to learn Common Lisp fist, I think the CL version is infinitely more clear and elegant. All that type information is redundant in the C# version, since in this case all you want to say about the types is that you don't care what they are. multiple-value-bind is among the longest function name in CL, and doing something that python does much better with syntax alone, perhaps Python is the new Lisp.
- dan00 17y ago"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." Aha. WTF? Ok, if I know what the code means, than I can read it. But that's only the case for C# and not for Common Lisp.
- StrawberryFrog 17y agoCode in unfamiliar languages always looks ugly. I know c# but not Lisp, and that just looks like ugly brackets salad to me. It can't help that your formatting as AWOL. So your statement that The C# one looks very long and ugly is entirely subjective.
- licoresse 17y agoOf course it is, and can I coin the "ugly brackets salad" phrase?
- StrawberryFrog 17y agoI coined it, but you can have it. See also: angry fruit salad http://catb.org/jargon/html/A/angry-fruit-salad.html http://catb.org/jargon/html/A/angry-fruit-salad.html