(define a 100) (define b 100) (define c 100) (let ([a 5] [b (+ a a)] [c (+ a b)]) (list a b c) )
The main command here is define, the two main usages are to bind a value to the result of an expression, and to bind an id to a procedure.
To bind an id to the value of an expression do
(define x 3)
To bind an id to a procedure you can do
(define (my-func arg1 arg2) (+ arg1 arg2))
Note that this is equivalent to:
(define my-func (λ (arg1 arg2) (+ arg1 arg2))
The Let expression allows us to make local name bindings, but the evaluation order of the bindings are done in some undefined order, meaning that they cannot depend on eachother.
(define a 100) (define b 100) (define c 100) (let ([a 5] [b (+ a a)] [c (+ a b)]) (list a b c) )
(define sq-cube (lambda (x) (let ([sqr (* x x)] [cube (* x sqr)]) (list sqr cube)) ) )
We can fix the above problem by nesting let statements or by using the let* expression which was defined exactly for having sequential let statements.
Also note that local name bindings do not update values, so if we had the following code
(define a 10) (let ([a 5]) (+ a 100))
Then the value of a is still 10. In general pure functions will never update values, which implies that every time a given function takes in a specfic set of values it will always return the same result and there are no side effects.
If no values ever change, then how do we actually do anything meaningful? Recursion.
Symbols can be thought of like enums.
(define-syntax list-of ; this is the initial name of macro (syntax-rules (for in) ; this are reserved keywords, match them literally ( (list-of result-element-expression for element-name in a-list) ; match this (map (λ (element-name) result-element-expression) a-list) ; map it to this ) ) )
Then (list-of e for x in ls)
will get replaced with (map (λ (x) e) ls)
Note that you can have recursive macros