I wanna make a separate “Scheme if you don’t know how to program” tutorial some other time!
We’re gonna use this example, a program that asks for two numbers, adds them, and displays the result.
(define (ask question)
(display question)
(newline)
(read))
(display
(+ (ask "What's the first number?")
(ask "What's the second number?")))
(newline)
(foo bar baz)
is the equivalent of what’s in C, Java, Javascript etc would’ve been written as:
foo(bar, baz);
A shorthand to count up parenthesis more easily!
Let’s look at this part as an example:
(display
(+ (ask "What's the first number?")
(ask "What's the second number?")))
To know how many parentheses are gonna be on that last line (in this
case three), you can count all the (
that is further to the left.
So in this example:
(define (ask question)
(display question)
(newline)
(read))
You are on the last line, “read”, and there are two parenthesis to the left of it.
You don’t have to look at the lines (display question)
and
(newline)
because they’re not to the left.
Also decrement the count for each closing parentheses in the same line:
(+ (ask "hi") (ask "there"))
has two closing parentheses.
Now, the difference between a macro and a function is…
Uh, let’s start with the similarity.
(foo bar baz quux)
(foo bar baz quux)
They look kinda similar.
A function gets the values of those variables. So if foo is a function, if bar is 1, baz is 2, and quux is 3, the function will see those numbers and will never know their names.
If foo is macro, it will see the whole (foo bar baz quux)
list and can
manipulate it as any other list. But it can never see the numbers.
A macro will return another list. For example, the macro might turn that example into
(let ((hi (+ baz baz)))
(+ hi (* bar bar)))
and that’s what’ll get called. So that is where those numbers will then be seen and used by the language.
That is kind of a pointless example but just to show what it can and can’t do.
Also, functions work from the inside out and macros from the outside in.
(foo bar (+ 13 14))
If foo is a function, it gets two arguments: whatever value bar has, and 27. It can’t see the plus sign because that’s already been done.
If foo is a macro, it instead sees that expression as a whole, even if there are other macros inside, the outermost macros are done first (so the complete opposite of functions in that regard). It can change the plus to a multiplication if you want. This is the wonder of macros: you can deal with stuff in an unusual order, or conditionally skip things or repeat them or whatever. With macros you can create new syntax, new language features, but in the end it’s got to be functions that do the actual work.
In Scheme, stuff like “if” and “let” and “define” are macros.
(if (< 1 3) 'yes 'no)
That becomes 'yes
.
(define (ask question)
(display question)
(newline)
(read))
That doesn’t become anything at all. But it binds a function to the variable “ask” in the top level, and that function displays the question, displays a newline, and reads (and becomes, or, “evaluates to”) the answer.
“Evaluate”, what’s with the lingo? Just means it turns something into another “value”. E-value-ate.
A function that doesn’t have a name is called a “lambda”.
(define (ask question)
(display question)
(newline)
(read))
is shorthand for
(define ask
(lambda (question)
(display question)
(newline)
(read)))
Functions are values, too, so (define another-ask ask)
works, for example, or:
(map ask (list "First question" "Second question" "Third question"))
That might show you the questions in a weird order in some Schemes, but you’ll end up with a list of the answers.
That’s right! All this was sneakily just a buildup to explaining lambda calculus! Which you now know, since you know programming, and all programming is based on it. Thanks, Alonzo Church!
(Note that macro names can’t be passed around the same way.)
At this point you’re not learning new grammar, you’re learning vocabulary, and a tutorial isn’t necessary anymore; instead, go look at a long list of existing functions and macros. They’re also what you are gonna use for making your own functions and macros. Many implementations have specific stuff here that’s kinda golden compared to the default standard old stuff.
I suggest you learn a specific implementation instead of just trying to learn all Scheme versions at once. Read your implementation’s docs and also look in the R5RS index.