Scheme is a programming language of the Lisp dialect. It is often called a functional language, and I do not like that, as it weakens the uniqueness of Lisp/Scheme, which I find are more than just functional languages.
Functional means you build computer programs using functions, as much as possible. Most often, these functions return the same result for the same argument. This helps you understand the program. But keep in mind that not all functions are like that, like those that use globally defined variables.
Programming in Scheme is tricky, as it differs a lot from C or Python like languages. There are concepts and ideas which are not present in those languages. For example, you can build computer programs in Scheme, without using variables, for loops, structures, or classes. Of course, many Lisp dialects and many Scheme implementations, do provide such features.
In computer programming, we expect consistent behaviour. But programs behave unexpectedly, crash due to bugs, or error due to changes and updates. Functional programming helps make computer programs easier to reason about and debug. There are several helpful ideas.
Immutability: once a variable is assigned a value, the value rarely changes.
Pure Functions: have no side effects and only depend on their inputs.
Functions are first-class citizens: allowing them to be passed as arguments to other functions and returned as values. This enables powerful abstractions and concise code.
Concurrency and parallelism: immutable data and pure functions make it easier to reason about code and avoid race conditions.
Expressiveness: powerful abstractions and expressive features, such as macros, that can lead to more concise and readable code.
It is alright if you do not understand any of the ideas above. Just keep in mind that Lisp/Scheme is not only a functional language. There is more to the complexity of Lisp/Scheme and to computational processes.
I will by and large talk about Scheme, a dialect of Lisp. Consider for a moment your native language and the number of its dialects. Lisp is like a native language for programming, and its dialects differ in complexity. The important difference between them is who made the dialect and for what purpose. Two of the widely known Lisp dialects are Common Lisp and Scheme. So, why Scheme? Because it has a smaller standard library, when compared to Common Lisp.
Scheme is standardized. Some smart people sat down and worked hard to create it. The standard is known as rnrs or RNRS. R is for Revised. N is for the version of the standard, likely 5, 6, or 7. The second R is for Report. Finally, S is for Scheme.
Strangely, you can find the standards online: r5rs ; r6rs.org ; r7rs.org .
What are the differences? Well, r5rs is the first well-received standard. But, like a movie analogy, where the sequel is always inferior, so was r6rs, considered bloated and too big for its own good. This is why, the filmmake- I mean, smart people, decided to step back, make as few changes to r5rs as possible, and called it r7rs. It was well received, but as always, taste is subjective.
There are many Scheme implementations differing in complexity, features, and purposes, as well as languages inspired by r5rs Scheme, and here is a list in no particular order: GNU Guile, GNU/MIT Scheme, Racket, Bigloo, Gambit Scheme, CHICKEN Scheme, Chez Scheme, TinyScheme, s7.
GNU Guile is an implementation of the Scheme programming language. It is a standalone programming language that extends the r5rs and r6rs standards. It is written in C and Scheme and integrates well with C code. Most functions in Guile have a Scheme and a C code version, allowing you to write in Scheme or C and connect the two systems.
The guile executable provides a stand-alone intepreter that is also a compiler. So, to follow the code examples in this writing, run the guile executable in a terminal. You will be greeted with a prompt such as:
user@computer:~$ guile
GNU Guile 3.0.7
Copyright (C) 1995-2021 Free Software Foundation, Inc.
Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.
Enter `,help' for help.
scheme@(guile-user)>
Here is an example of evaluating an expression, which adds together numbers three and seven.
scheme@(guile-user)> (+ 3 7)
$1 = 10
The expression result is saved in $1
and can be used again.
scheme@(guile-user)> (+ $1 3)
$2 = 13
To exit guile, simply write (quit)
as the expression.
scheme@(guile-user)> (quit)
user@computer:~$
For clarity, I will from now on remove scheme@(guile-user)
and keep only >
.
Here are Lisp/Scheme concepts, as many as I can think of. Come back to this as you read to check your level of understanding.
Anonymous functions: Scheme allows you to define functions without giving them a name, called lambda expressions.
Higher-order functions: Functions can take other functions as arguments or return functions as results.
Macros: Scheme’s powerful macro system allows you to define new syntactic constructs that are translated into regular Scheme code at compile time.
Recursion: Scheme encourages the use of recursion as a fundamental programming technique.
Tail call optimization: Scheme implementations perform tail call optimization, which allows some recursive functions to execute in constant space.
Lexical closures: Scheme supports lexical closures, which allow functions to capture and remember the environment in which they were created.
Memoization: Scheme allows for memoization, a technique used to cache the results of expensive function calls for future use.
Continuations: Scheme supports continuations, which represent the future of computation at any given point in a program’s execution.
Dynamic bindings: the scope of a parameter variable is determined by the order of function calls at runtime rather than by the lexical structure of the program.
Lambda Calculus: Scheme is based on lambda calculus, a mathematical formalism for expressing computation. Scheme supports currying and recursive anonymous functions.