What is a y-combinator?
stackoverflow.com
stackoverflow.com
http://stackoverflow.com/questions/93526/what-is-a-y-combina...
sub {
my $builder = shift;
return sub {
my $n = shift;
return $builder->($builder)->($n);
};
}->(
sub {
my $recurse = shift;
return sub {
my $n = shift;
say "$n"; # Just a way to test
if (0 == $n) {
return 1;
}
else {
return $n * $recurse->($recurse)->($n - 1);
}
};
}
)->(5);
I was confused about the "perl can't do this" part.But when you drop the pretenses, you're still doing assignment. (Though otherwise you've perfectly duplicated the pattern.)
use strict; use warnings; use signatures;
sub ( $builder ) {
return sub ( $n ) {
return $builder->($builder)->($n);
};
}->(
sub ( $recurse ) {
return sub ( $n ) {
if (0 == $n) {
return 1;
} else {
return $n * $recurse->($recurse)->($n - 1);
}
};
}
)->(5);I still think that my email was accurate as of 2005.
I've never understood why y-combinator is useful or impressive. Interesting, maybe, but not really useful.
Although the Fexl language itself has syntax for recursive definitions, it translates everything to combinators internally, so there are no "symbol tables" or "environments" at run time. Therefore it uses the Y combinator to implement those recursive definitions.
A while ago I wrote this detailed example: http://news.ycombinator.com/item?id=2719635
tl;dr here is a non-recursive definition of the append function for two lists:
(Y \append \x\y x y \h\t cons h; append t y)
If you need more parentheses for clarity, here you go: (Y (\append \x\y x y \h\t cons h (append t y)))http://www.dsi.uniroma1.it/~labella/absMcAdam.ps (or search with Google for an HTML translation).
That may sound like bickering over a fine point, but I'm just saying that combinators can be more than a theoretical tool.
It seems reasonably fast for my purposes so far, and the expansion rule is just a one-liner: https://github.com/chkoreff/Fexl/blob/master/src/Y.c
See http://www.paulgraham.com/noop.html for evidence that he isn't a big fan of OO.
Hint.
(define (init-counter)
(local
((define counter 0)
(define (inc) (set! counter (add1 counter)))
(define (dec) (set! counter (sub1 counter)))
(define (current-count) counter))
(values inc dec current-count)))
Then you can just import this code into wherever you want to use it and do something like: (define-values (counter++ counter-- current-count) (init-counter))
Plenty of people have said data structures are a poor mans functions. I think it's in that famous list of programmer quotes collected by alan perlis that everyone inevitably comes across at some point.In many cases where you want object orientation something like this will be sufficient. No need to go the whole way with inheritance and whatnot.
Nice trick with your little module-in-a-box there. I think it's roughly analogous to the technique I used in my "handy_module" example here: http://news.ycombinator.com/item?id=2580717 .
It's interesting to note though that the difference between this and a data structure is not that great. I haven't looked into it but I'm certain I've read somewhere that data structures as implemented in racket (which is what my example is written in) actually desugar into something like my example code.
I still like to use this technique here and there, especially when there will only be one copy of the structure in use in my program. This is because it's simply more convenient to write something like (counter++) rather than declaring a global COUNTER and typing in (set! COUNTER (add1 COUNTER)) etc.
But recently I even "de-objectified" a body of Perl code I wrote (a standalone server called "loom" https://loom.cc/source).
I systematically refactored it to get rid of all $object->function constructs. I ended up with a flat name space with names like trans_get, trans_put, span_encrypt, diceware_passphrase, file_update, dttm_as_cookie, api_grid_move, valid_id, trimblanks, token_get, etc. etc.
I even have a little script in there called "show_subs" which lists all the routine names in alphabetical order. There are 410 of them.
You might call that a "polluted" name space, but to me it smells like clarity. I can now look at any snippet of code completely out of context and know exactly what it does.
You might say that the downside is that each piece of code is not "configurable", meaning that it can't operate on different types of things depending on context. If and when that ever became necessary, I could easily manage it. But I never found it to be necessary.
By the way, this discussion reminds me of this article posted earlier: http://erlang.org/pipermail/erlang-questions/2011-May/058769... . I look at the list of functions he exports there and I think yeah, I bet I could use those in a heartbeat without a second thought.
People who see it and recognize it are the type of people he wants to catch attention from(hackers). Suits, would see it and ignore it.