RE: What's so cool about Scheme? (2003)
people.csail.mit.edu
people.csail.mit.edu
It turned out to be extremely straightforward to map objects to closures. Took <100 lines of documented code!
obj.method(& args) => (obj :method & args)
I even have a basic 2d sprite-based game engine here[2] (on top of Swing!).[1] https://github.com/divs1210/cljos [2] https://github.com/divs1210/bakait
Milner showed how to encode the lambda calculus as message passing but "parallel computation has no 'good' encoding into functional computation". So message passing is fundamental. Plus in the end there are parts of your system that you are going to have to model in this way anyway. e.g. IPC. Personally it helps me psychologically to have a common model for everything even if when I am e.g. composing functions I'm not really thinking about messages.
In order to map algorithms to parallel computing for non-trivially parallel problems you'll need things like futures, message passing, etc. that gets you back into specifying the dirtier low-level parts of the algorithm again.
Its more idiomatic in a procedural language because your'e doing all of this work all the time any way. It is still a hassle, it just doesn't mess with the "Elegance."
The spot where I'm finding that functional programming just cannot help me is when I really do need to have all the cooks in the same kitchen to get good performance. Those situations exist in a world of highly refined, weapons-grade side effect, and the only thing to be done for it if you find yourself there is to come to terms with that fact and get on with your job.
Really multi-core machines have only been standard for about 10 years now? Before then, multi-processor machines filled more niche roles (Servers, HPC, etc). Now my phone has 4 cores. Parallel computing is becoming more common because all of the code you write will run on a multi-core system.
I definitely see how writing multi-threaded code in a lisp in 2003 would have been less savory. Things are definitely better now. Things like Par & Repa can do some amazing things in Haskell. I'm sure there are more some great packages out for scheme that are similar . I don't think we're 100% there yet. Who knows where we'll be in another 10 years?
http://emacswiki.org/emacs/GuileEmacs
Hopefully, people will build IDE's comparable to IntelliJ with it.
The first comment of https://brendaneich.com/tag/history/ have this perl:
"As I’ve often said, and as others at Netscape can confirm, I was recruited to Netscape with the promise of “doing Scheme” in the browser. "
Edit: After a second read, I get now that you were being sarcastic about the koan. Silly me, I don't get those over the net :)
Once upon a time, I didn't know about their existence and didn't have anyone to point me in that direction, and I converged in pretty much the same thing when I was asked to implement an automatic forms generator from data. It feels silly when you just discover something cool that is old news.
It's a poor atom-blaster that doesn't point both ways -- Hober Mallow
Meh... [1][2][3][4]
[1] http://www.biwascheme.org/
[2] https://github.com/jcoglan/fargo
;; Set the background green, and show some content
;; on the browser.
(void (call-method body "css" "background-color" "lightgreen"))
(void (call-method ($ "<h1>Hello World</h1>") "appendTo" body))
I love Racket. Yet, I'm not enough of a masochist to use Whalesong instead of Javascript just to prove my love.What's more, this enforces good object-orientation: this is a reimagining of the single-responsibility principle because closures are objects that literally do one thing.
Closures also enforce the open-close principle. Once it's closed it's closed.
The result is that you get a lot of good OO practices for free.
It is interesting because this is exactly how C++11 implements lambdas. Still Scheme's closures are more convenient although C++14 is closing the gap.
(Yes, the readability of the resulting code is very suspect. Just experimenting!)
# Provide a prefix syntax that constructs a unary procedure from just a body.
(extend-parser "^" (mac (x) `(proc (?) ,x)))
# Provide a prefix syntax that constructs a unary macro from just a body.
(extend-parser "%" (mac (x) `(mac (?) ,x)))
# Apply an anonymous macro to 4, resulting in definitions for cad{1,4}r
# being generated then evaluated:
(
%`(seq ~(map ^(let i (codepoint-count ?)
sym (string-to (sprint "ca" ? "r"))
`(def ,sym (proc (xs) (ith-element ,i xs))))
(map ^(apply sprint (repeat "d" ?))
(range 1 ?))))
4)
# What ended up being evaluated at the top-level:
# (seq (def cadr (proc (xs) (ith-element 1 xs)))
# (def caddr (proc (xs) (ith-element 2 xs)))
# (def cadddr (proc (xs) (ith-element 3 xs)))
# (def caddddr (proc (xs) (ith-element 4 xs))))C++11 lambdas which capture free variables by reference can not be returned from a function in which the free variables occur, and be expected to work, because the function's variable (a free variable to the lambda) may no longer refer to memory allocated for use as the variable.
That's not true for Scheme. Scheme's underlying implementation of lambda and function call means that true closures are created: if a lambda refers to a variable which is not local to (or a parameter to) the lambda, then that free variable belongs to an environment, whose lifetime isn't delimited by popping a stack and returns, and is therefore still live as long as some closure (or stack activation frame) refers to it. Return of a lambda with free variables will work in Scheme, and can fail in C++11.
However, that's not what I meant when I wrote that. I was referring this quote:
"being able to concisely define executable "objects" (closures), inline if necessary, is very useful"
The fact that you can define inline executable objects is indeed very useful, and C++ does exactly that: an inline mangled class instantiated bounded to one variable.
It would be cool to have free variable in C++ in the same way that Scheme handles it, but I don't think the language would get there anytime soon (Gee, it is still cumbersome to have recursive lambdas).