Recommended you run in turbo mode.
Code and data use the same syntax for lists: (stuff...) where stuff is a list of things separated by whitespace such as symbols (alphanumerical characters and most other non-whitespace characters on your keyboard besides (, ), ', #, and ;), numbers (integers only for now), booleans (#t for true and #f for false), or other lists with the same recursive syntax.
When a list is evaluated, the function goes at the start of the list, and the arguments follow it: for example, (+ 1 3) or (* 7 6) or (cons 1 (cons (* 6 5) 4)).
Symbols evaluate to variables, which you set for the first time with the define special form, then use either set! or define after that, like this:
(define my-variable 4)
(set! my-variable 4)
The alternative syntax for define has not been implemented yet.
The ' character before anything expands into (quote <that thing>), which evaluates as literally <that thing> rather than it's value. For example: (cons 'a '(b c 1)) does not treat a b or c as variables because they were quoted.
Numbers and booleans (#t for true and #f for false) are self-evaluating, that is they evaluate as themselves.
The begin special form lets you do stuff in sequence and only returns the value of the last one, for example
(set! x 3)
The if special form is like if/else in scratch: if the first thing is true (anything which isn't #f is considered true btw), the second will be evaluated, otherwise the third will, or it will return void if there is no 3rd thing. Example:
(if (< x 3)
Lambdas are hard to explain. They are custom procedures, a bit like custom blocks in scratch, but they are first class, and are like rings in Snap!. This means a variable can be one, or you can pass one to a function. I can't really explain it fully here, so read SICP (linked below).
You can define functions like this:
(define square (lambda (x) (* x x)))
(square 3) ; is 9
There's an alternative syntax for define to define functions, but it's not yet implemented.
You can make loops using recursion. If you write it tail recursively, it won't consume too much stack space.
(define write-all-nums (lambda (num)
(if (= num 0)
(write-all-nums (- num 1))))))
(define factorial (lambda (num)
(if (= num 0)
(* num (factorial (- num 1))))))
(factorial 4) ;should be 24
You can even make higher order functions:
(define map (lambda (f lst)
(if (eq? lst '())
(cons (f (car lst)) (map f (cdr lst))))))
(map (lambda (x) (+ x 1)) '(1 2 3)) ; should be (2 3 4)
Lambda alone even makes scheme turing complete!
If you haven't read it yet, I'd highly recomend reading SICP: https://mitpress.mit.edu/sicp/full-text/book/book.html
This is a test for an interpreter for the programming language "Scheme" which I'm making in scratch. It's is now powerful enough to be considered a small subset of scheme. It has lists, quoting, numbers, symbols, variables, if, begin, lambda and the primitives +, -, *, /, mod (integer division only), <, >, =, eq?, cons, car, cdr, read, eval, display, write, and apply.
Inspired by the textbook SICP: https://mitpress.mit.edu/sicp/full-text/book/book.html
Fixed a bug involving defining a variable as the value of an expression that called a custom procedure
(Anyone who finds a bug will get credit here)
- Doesn't work at all, discovered by hardmath123
- Mathematical operators don't work, discovered by me
- If doesn't work, discovered by Jonathan50
- Variables don't work, discovered by Jonathan50
- If doesn't work properly, discovered by me
- Variable not bound error when attempting to define cadr, discovered by Jonathan50
- Set-car doesn't work, discovered by Johnathan50