|
|
clipka wrote:
> Not that I'd say Scheme or Lisp would suck, but... well, I don't have the
> slightest clue how to *decipher* it - could be ROT13-encrypted ancient egypt,
> from all I see :P
Errata: read v as vec. :P
>> (define vec (make-vector 10))
This is clear enough, I guess: defines vec to be the result of
(make-vector 10), which should be self-evident as well: makes a vector
(array) of 10 elements.
>> ((range 0 9) '() (lambda (i o) (vector-set! vec i (* i i)) o))
This is not plain Scheme, it's an idiom I use. Let's decompose it.
First: in Lisp, anything in the head of a list (everything between
parentheses) should be a function or a macro, should the list be
evaluated. An unevaluated list is like '(1 23 "foo") etc. It's said to
be quoted.
For instance:
(+ 1 2 3) results in the application arguments 1,2,3 to function +, thus
yielding 6
'(+ 1 2 3) results in the list with the symbol + and numbers 1,2,3.
So from now on it's obvious that (range 0 9) results in a function,
otherwise it wouldn't be in the head.
range is a handy function that returns, guess what!, another function.
The function returned is an *iterator* for the given "range", in this
case, 0 to 9.
The *iterator function* so returned gets 2 parameters: the /initial
value/ to be used as first result and a /reducer function/ that takes
the current iteration step and the current result and returns a new result.
So, '() is the /initial value/ and (lambda (i o) (vector-set! vec i (* i
i)) o) is the /reducer function/ I provided. Both are fed to the
*iterator function* returned by (range 0 9) which will successively feed
the /reducer/ the current iteration item and the result so far.
In other words: range returns a "functional" for loop. :) (I don't like
Scheme's standard loop mechanism, "do")
(lambda args body ...) is Scheme's way of creating an anonymous
function. I could as well just previously defined it and given the name
to the iterator, say:
(define powerize (lambda (i o) (vector-set! vec i (* i i)) o))
or sugared:
(define (powerize i o) (vector-set! vec i (* i i)) o)
and then:
((range 0 9) '() powerize)
anyway, (vector-set! vec i (* i i)) sets vector vec element i (vec[i] in
C) to be (* i i). And what is i? i is the first argument to the
/reducer function/, which represents the current iteration item, in this
case a number in the 0-9 range.
Summing up: given i = from range 0 to 9, it will set the current vector
element to i*i.
Let's put c and my scheme idiom side-by-side:
((range 0 9) '() (lambda (i o) (vector-set! vec i (* i i)) o))
for(int i=0;i++<10;)vec[i]=i*i;
whoa! Just remember it's all but a user-defined function with no
syntatic sugar provided by macros wrapping it up. I could just as well
provide one such sugared version:
(define-syntax for
(syntax-rules (=>)
((for i from to => body ...)
((range from to) #t (lambda (i o) (begin body ...) o)))))
(for i 0 9 => (@! vec i (* i i)))
for(int i=0;i++<10;)vec[i]=i*i;
Much better. :)
@! is my personal alias for vector-set!
Also, not seen here is the hability to actually have some useful result.
I mean, setting elements of an array is pretty much an imperative
operation, but still you could simply pass the result of the whole call
to yet another function using the vector just set, simply by doing:
((range 0 9) vec (lambda (i o) (vector-set! vec i (* i i)) o))
and then, using it like:
(vector-ref ((range 0 9) vec (lambda (i o) (vector-set! vec i (* i i))
o)) 2) => 4
Something you can't do with the built-in C for loop.
Was it really that hard? :)
BTW, aside from not mentioning it is a lexically-scoped language, you've
just learned pretty much all the basic semantic of Scheme. It is that
simple a language. Even though my particular idiom may sound a little
daunting at first... :P
Post a reply to this message
|
|