Live data from Hacker News

I’ve Consed Every Pair

medium.com

81–90 of 228 posts

Re: I’ve Consed Every Pair

#81
post #14

The most important thing I ever learned from Professor Norvig was how to not get fat at Google. He said, "Never take a tray. If it won't fit on one plate, it's too much". A wise man. I mean I suppose some of the stuff I learned from his textbook was pretty useful too.

What advice would you give to those of us who struggle with our weight, regardless of the size of our plate, who came here to discuss lisp and not what the author of the blog post said to you one time about food portions?

Re: I’ve Consed Every Pair

#82
post #14

The most important thing I ever learned from Professor Norvig was how to not get fat at Google. He said, "Never take a tray. If it won't fit on one plate, it's too much". A wise man. I mean I suppose some of the stuff I learned from his textbook was pretty useful too.

What advice would you give to those of us who struggle with our weight, regardless of the size of our plate, who came here to discuss lisp and not what the author of the blog post said to you one time about food portions?

Write down what you eat. Even if you change nothing, you'll re-consider grazing/snacking. Write it down before you eat it for extra effectiveness.

Shameless plugs in my post history. But to be clear, even a sheet of paper can be tremendously helpful.

Re: I’ve Consed Every Pair

#83

Earlier quoted context omitted.

Not at all. I share your frustration. Closures on a server are a powerful way of representing data flows. But they come at a cost: the links expire after some time. How do you strike a balance? The simplest way is to put in the extra time to make everything into a persistent link. But, that's equivalent to removing all the benefits of lexical scoping. If you've ever created an inner function before, you know how powe…

Since this is getting a surprising amount of interest, let me sum up the technique here. It's really not hard to implement it in Javascript using Express. 1. inside of your express endpoint, create a closure that captures some state. For example, the user's IP address. (This is a dumb example, but the point is that you can capture whatever state you want . Some cases are mentioned here: http://paulgraham.com/road.htm…

I mean, I can tell you right now why I'm not using it circa 2020, nor do I expect I shall in future. For sure, it's clever and it's elegant, a brilliant hack - but it's not durable, and in my line of work that counts for more.

On the one hand, as you note, this can't scale horizontally without the load balancer knowing where to route a request based on the fnid, which means my load balancer now has to know things it shouldn't - and that knowledge has to be persisted somewhere, or every session dies with the load balancer.

On the other hand, even if I teach nginx to do that and hang a database or something off it so that it can, with all the headaches that entails - this still can't scale horizontally, because when one of my containers dies for any reason - evicted, reaped, crashed, oomkilled because somebody who doesn't like me figured out how to construct a request that allocates pathologically before I figured out how to prevent it, any number of other causes - every session it had dies with it, because all that state is internal to the runtime instance and can't be offloaded anywhere else.

So now my cattle are pets again, which I don't want, because from a reliability standpoint shooting a sick cow and replacing it with a fresh one turns out to be very much preferable to having to do surgery on a sick or dying pet. Which I will have to do, because, again, all the persisted state is wrapped up tight inside a given pod's JS runtime, so I can't find out anything I didn't know ahead of time to log without figuring out how to attach a debugger and inspect the guts of state. Which, yes, is doable - but it's far from trivial, the way Lisps make it, and if the pod dies before I can find out what's wrong or before I'm done in the debugger, I've got a lot less to autopsy than a conventional approach would give me. And that's no less a problem than the rest of it.

Yes, granted, the sort of software you describe is incredibly elegant, a beautifully faceted gem. It's the sort of thing to which as a child I aspired. But as it turns out, here thirty years on, I'm not a jeweler, and the sort of machine my team and I build has precious little need for that sort of beauty - and less still for the brittleness that comes with it. Durability counts for much more, because if our machines break and stay broken long enough, the cost is measured in thousands or millions of dollars.

That's not hyperbole, either! Early one morning last November, I ran two SQL queries, off the top of my head, in the space of two thirds of a minute. When all was eventually said and done, the real value of each of those forty seconds, in terms of revenue saved, worked out to about $35,000 - about $1.4 million, all told, or seven hundred thousand dollars per line of SQL. And not one of the people who gave us all that money ever even knew anything had been wrong.

Granted that a couple of unprecedented SQL queries like the ones I describe, written on nothing but raw reflex and years of being elbow deep in the grease and guts of that machine and others like it, constitute a large and blunt hammer indeed. But - because we built that machine, as well as we knew how, to be durable and maintainable above all else - in a moment which demanded a hammer and where to swing it, both were instantly to hand. In a system built as you describe, all gleaming impenetrable surfaces between me and the problem that needed solving right then, how could I have hoped to do so well?

Only through genius, I think. And don't get me wrong! Genius is a wonderful thing. I wish I had any of it, but I don't. All I know how to be is an engineer. It's taken me a long time to see the beauty in that, but I think I'm finally getting a handle on it, these days. It's a rougher sort of beauty than that to which I once aspired, that I freely concede, and the art that's in it is very much akin to something my grandfathers, both machinists and one a damned fine engineer in his own right, would have recognized and I hope might have respected, had they lived to see it.

Do you know, one of those grandfathers developed a part that went on to be used in every Space Shuttle orbiter that ever flew? It wasn't a large part or a terribly critical one. You wouldn't think much of it, to look at it. But he was the man who designed it, drew it out, and drew it forth from a sheet metal brake and a Bridgeport mill. He was the man who taught other men how to make more of them. And he was a man who knew how to pick up a hammer and swing it, when the moment called for one. He was possessed of no more genius than am I, and his work had no more place in it for the beauty of perfectly cut gemstones than does mine. But he was a smart man, and a knowledgeable man, and not least he was a dogged man. And because he was all those things, my legacy includes a very small, but very real, part in one of the most tangible expressions of aspiration to greater, grander things that our species has ever yet produced. Sure, the Space Shuttle was in every sense a dog, a hangar queen's hangar queen. But, by God, it flew anyway. It 'slipped the surly bonds of Earth, and touched the face of God' - and next time, we'll do better, however long it takes us. And, thanks to my grandfather's skill and effort, that's part of who and what I am - and there's a part of me in that, as well.

No gemstone that, for sure! It has its own kind of beauty, nonetheless - the kind that leaves me feeling no lack in my paucity of genius, so long as I have an engineer's skill to know when and how to swing a hammer, and an engineer's good sense to leave myself a place to land it. If that was ever in doubt, I think it can only have been so until that morning last November, when I saved ten years' worth of my own pay in the space of forty seconds and two perfect swings of exactly the right hammer.

There's a place for the beauty of gemstones, no doubt - for one thing, in seeing to it this very long comment of mine isn't lost to the vagaries of a closure cache. And I appreciate that, for sure! It'd be a shame to have wasted the effort, to say nothing of any small value that may cling to these words.

But there's a place for the beauty of hammers, too.

Re: I’ve Consed Every Pair

#84

Earlier quoted context omitted.

Not at all. I share your frustration. Closures on a server are a powerful way of representing data flows. But they come at a cost: the links expire after some time. How do you strike a balance? The simplest way is to put in the extra time to make everything into a persistent link. But, that's equivalent to removing all the benefits of lexical scoping. If you've ever created an inner function before, you know how powe…

Since this is getting a surprising amount of interest, let me sum up the technique here. It's really not hard to implement it in Javascript using Express. 1. inside of your express endpoint, create a closure that captures some state. For example, the user's IP address. (This is a dumb example, but the point is that you can capture whatever state you want . Some cases are mentioned here: http://paulgraham.com/road.htm…

This is really funny; Back in the warcraft 3 days, we used to do the same thing inside its scripting language --- to attach some data to a timer, we would exploit the fact that a timer is in fact just a 'void *' underneath: so the pointer address gave us the unique ID. We would stash data associated with the timer in a global hash table. Then, in the callback of the timer, we would read the data back from the global hash table!

Your exposition took me a trip down memory lane to middle/high school. Thank you for this :)

- References: https://www.thehelper.net/threads/jass-timers-and-how-to-pas...

Re: I’ve Consed Every Pair

#85

Earlier quoted context omitted.

What advice would you give to those of us who struggle with our weight, regardless of the size of our plate, who came here to discuss lisp and not what the author of the blog post said to you one time about food portions?

Write down what you eat. Even if you change nothing, you'll re-consider grazing/snacking. Write it down before you eat it for extra effectiveness. Shameless plugs in my post history. But to be clear, even a sheet of paper can be tremendously helpful.

As a person who recalls every bite and gains weight at one meal a day with no snacking at all, this is not helpful. I'm still looking for advice on why I'm being told to count my food intake in a lisp discussion.

Re: I’ve Consed Every Pair

#86

Earlier quoted context omitted.

> it never quite came through. Hard disagree. The Clojure ecosystem is great.

It's obscure enough that it perhaps proves my point. Nonetheless, I'll have to look at it.

If you haven't heard of Clojure, you probably haven't listened to a Rich Hickey talk. They're worth it even if you don't use Clojure. "The Value of Values" and "Simple Made Easy" in particular.

Re: I’ve Consed Every Pair

#87

Earlier quoted context omitted.

It's a little sad that it's declined so far. In a way, it's a victim of its own success--it's so easy to write a lisp system that literally dozens, if not hundreds, of variants sprang up. The community was divided, and it never quite came through. IIRC, our fearless leader PG made his zillions using Lisp.

The division was never a problem during the heyday. The decline in Lisp in fact started at the height of standardization. > it's so easy to write a lisp system Have you tried it, and how far did you get? Making a Lisp system useful for production is pretty brutal. 13 years into it you will be debugging some eleven-year-old GC or compiler bug. People think it's easy because they visualize the job as being done when so…

Maybe it declined for other reasons, but my impression was that the Lisp world was very splintered. I certainly can't think of any other example of a set of quite similar languages that's anywhere near as large.

The Xerox Dandelion and friends was a thing to behold. If you ever got to touch one, you never forgot it.

In my school, implementing a basic Lisp interpreter was part of a required class in the CS curriculum. (If it's not still, everywhere, well, then for shame.)

Yeah, production is something else entirely. By "easy", I mean that dozens if not hundreds of people were tempted to write their own slightly better Lisp. Many of those did reach a production-ish level. But then what? There was no flag to rally around--just lots and lots of niche systems.

I'm not sure. I think if the community had rallied around Common Lisp or Scheme, or maybe just those two, it might have ruled the world. It just didn't happen.

And I'm miserably sad about that. What do we have now? Elisp is great, but I can't build production on emacs. I'll look at Clojure, but I'm dubious. Python is kind of lispy, but has had its own destructive schism. And C++ marches on--somewhere buried in there is a mildly functional lisp, using the worst of all possible syntaxes.

Re: I’ve Consed Every Pair

#88

Earlier quoted context omitted.

Well this is certainly the coolest thing I've read today. I've been trying to grok closures and this helps a bit. Is there a reason to not use the global hash table itself to store the state instead of a closure? This seems to be trading a database with memory. This also seems to be harder to interrogate, what if I want to go in and see what's currently outstanding, instead of going to Firebase, I'll need to go throu…

The biggest difference is the “...” assignment to fn. The idea is similar to AWS Lambda — write functions, store those functions, and then call them later when you need them. I’ve minimal Lisp experience, but from my perspective, a closure is a function you can store in a variable that’s defined with a scope, or a set of arguments/variables used in your function, that often (but not always) includes variables from th…

It's not all that similar to AWS Lambdas in concept or in execution. Those are stateless; to a very good first approximation, they're just a single-route web server with all the boilerplate abstracted away, and that starts up a fresh instance to handle each request and is shut down again immediately after.

What 'sillysaurusx describes is much more similar to what, in Scheme and elsewhere but these days mainly there, is called "continuation-passing style". It's a way of pausing a partially completed computation indefinitely by wrapping it up in a function that closes over the state of the computation when you create it, and calling that function later to pick up from where you left off when you're ready to proceed again.

I suppose you could maybe do that with an AWS Lambda, but because the technique relies strongly on the runtime instance staying around until the computation finishes, it would probably get expensive. Lambdas aren't priced to stay running, after all.

As a side note, it's worth mentioning that the "AWS Lambda" product, which whatever its virtues isn't actually a lambda, derives its name from the lambda calculus, where I believe the concept of anonymous first-class functions originates. I don't recommend reading about the lambda calculus itself unless you're up for a lot of very heavy theory, but it's worth knowing that, especially in the Lisp world and realms adjacent, you'll often see the term 'lambda' used in a sense which has nothing to do with the AWS product, but rather refers to a form of abstraction that relies on defining functions which retain access to the variable ("lexical") scopes in which they were created, even when called from outside those scopes. Javascript functions have this property, which is why they're capable of expressing the technique 'sillysaurusx describes, and it gives them a lot of other useful capabilities as well.

Re: I’ve Consed Every Pair

#89

Earlier quoted context omitted.

Write down what you eat. Even if you change nothing, you'll re-consider grazing/snacking. Write it down before you eat it for extra effectiveness. Shameless plugs in my post history. But to be clear, even a sheet of paper can be tremendously helpful.

As a person who recalls every bite and gains weight at one meal a day with no snacking at all, this is not helpful. I'm still looking for advice on why I'm being told to count my food intake in a lisp discussion.

[deleted]

Re: I’ve Consed Every Pair

#90

Earlier quoted context omitted.

Since this is getting a surprising amount of interest, let me sum up the technique here. It's really not hard to implement it in Javascript using Express. 1. inside of your express endpoint, create a closure that captures some state. For example, the user's IP address. (This is a dumb example, but the point is that you can capture whatever state you want . Some cases are mentioned here: http://paulgraham.com/road.htm…

Well this is certainly the coolest thing I've read today. I've been trying to grok closures and this helps a bit. Is there a reason to not use the global hash table itself to store the state instead of a closure? This seems to be trading a database with memory. This also seems to be harder to interrogate, what if I want to go in and see what's currently outstanding, instead of going to Firebase, I'll need to go throu…

It works a lot better in a proper Lisp, where the REPL and debugger are first-class citizens. In Javascript, you can do it, but it's a dancing bear at best; as you note, the observability is poor to nil without heroic effort, and scalability's a problem too.
Post reply on HN