Skip to content

SCHEME


Scheme is a minimalist, functional programming language with a simple and consistent syntax. Its design emphasizes simplicity and expressiveness, making it a great language for learning programming concepts. Below is a complete breakdown of Scheme syntax, covering its core components and features.


1. Basic Syntax Rules

  • Prefix Notation: All expressions are written in prefix notation, meaning the operator or function comes before the arguments.
    (+ 2 3) ; => 5
    
  • Parentheses: Parentheses () are used to group expressions. Every expression in Scheme is enclosed in parentheses.
  • Whitespace: Spaces or newlines separate elements within an expression.

2. Data Types

Scheme supports several basic data types:

#### a. Numbers - Integers: 42, -7 - Floating-point: 3.14, -0.5 - Rationals: 1/2, -3/4

#### b. Booleans - #t (true) - #f (false)

#### c. Characters - Written with a #\ prefix: #\a, #\space, #\newline

#### d. Strings - Enclosed in double quotes: "Hello, Scheme!"

#### e. Symbols - Used as identifiers or names: 'symbol, 'x, 'my-var

#### f. Lists - A fundamental data structure in Scheme: (1 2 3), '(a b c)

#### g. Pairs - Created with cons: (cons 1 2) => (1 . 2)


3. Expressions

Every Scheme program is made up of expressions. An expression can be: - A literal value: 42, "hello" - A variable reference: x, my-var - A function call: (+ 2 3) - A special form: (define x 10)


4. Variables and Binding

  • define: Binds a value to a variable.
    (define x 10)
    (define name "Alice")
    
  • let: Creates local bindings.
    (let ((x 10) (y 20))
      (+ x y)) ; => 30
    

5. Functions

  • Defining Functions: Use define to create a function.
    (define (square x)
      (* x x))
    (square 5) ; => 25
    
  • Lambda Functions: Anonymous functions created with lambda.
    (define square (lambda (x) (* x x)))
    (square 5) ; => 25
    

6. Control Structures

  • Conditionals:
    • if: Evaluates a condition and returns one of two values.
      (if (> 5 3) "Yes" "No") ; => "Yes"
      
    • cond: A multi-branch conditional.
      (cond
        ((> 5 10) "Greater")
        ((= 5 5) "Equal")
        (else "Less")) ; => "Equal"
      
  • Logical Operators:
    • and: Returns #t if all arguments are true.
      (and #t #f) ; => #f
      
    • or: Returns #t if any argument is true.
      (or #t #f) ; => #t
      
    • not: Negates a boolean value.
      (not #t) ; => #f
      

7. Lists and Pairs

  • Creating Lists:
    • Use list or quote notation.
      (list 1 2 3) ; => (1 2 3)
      '(1 2 3)     ; => (1 2 3)
      
  • Accessing Elements:
    • car: Gets the first element of a list.
      (car '(1 2 3)) ; => 1
      
    • cdr: Gets the rest of the list.
      (cdr '(1 2 3)) ; => (2 3)
      
  • Constructing Pairs:
    • Use cons.
      (cons 1 2) ; => (1 . 2)
       (cons 1 lst); => adds item to from of list
      

8. Recursion

Scheme relies heavily on recursion for iteration. - Example: Factorial

(define (factorial n)
  (if (= n 0)
      1
      (* n (factorial (- n 1)))))
(factorial 5) ; => 120


9. Higher-Order Functions

Functions that take other functions as arguments or return functions. - map: Applies a function to each element of a list.

(map square '(1 2 3 4)) ; => (1 4 9 16)
- filter: Filters a list based on a predicate.
(filter even? '(1 2 3 4 5)) ; => (2 4)
- lambda: Creates anonymous functions.
(map (lambda (x) (* x x)) '(1 2 3)) ; => (1 4 9)


### 10. **Input/Output**
  • display: Prints a value to the output. scheme (display "Hello, Scheme!") ; => Hello, Scheme!
  • newline: Prints a newline. scheme (newline)
  • read: Reads input from the user. scheme (define x (read))

11. Quoting and Quasiquoting

  • Quote ('): Prevents evaluation.
    '(1 2 3) ; => (1 2 3)
    
  • Quasiquote (`): Allows selective evaluation with ,.
    `(1 ,(+ 2 3) 4) ; => (1 5 4)
    

12. Macros

Scheme allows defining macros for metaprogramming. - Example: Simple Macro

(define-syntax when
  (syntax-rules ()
    ((_ condition body ...)
     (if condition (begin body ...)))))
(when #t (display "Hello")) ; => Hello


13. Modules and Libraries

  • Use define-module or import (depending on the Scheme implementation) to organize code into modules.
    (define-module (math)
      (export square)
      (define (square x) (* x x)))
    

Summary of Scheme Syntax

Feature Example
Numbers 42, 3.14, 1/2
Booleans #t, #f
Strings "Hello"
Lists (1 2 3), '(a b c)
Variables (define x 10)
Functions (define (square x) (* x x))
Conditionals (if (> 5 3) "Yes" "No")
Recursion (define (factorial n) ...)
Higher-Order (map square '(1 2 3))
I/O (display "Hello")
Quoting '(1 2 3), `(1 ,(+ 2 3))

This breakdown covers the entirety of Scheme syntax. It’s a simple yet powerful language that forms the foundation for many advanced programming concepts!


not Function

  • Syntax: (not value)
  • Purpose: Negates a boolean value.
  • Returns: #t if value is #f, otherwise #f.

#### Examples:

(not #t)  ; => #f
(not #f)  ; => #t
(not (= 3 3))  ; => #f (because (= 3 3) is #t)
(not (> 5 10)) ; => #t (because (> 5 10) is #f)

Outputs:

#f
#t
#f
#t


Predicate Functions for Numbers

Predicate functions test conditions on numbers and return #t or #f.

#### a. = (Equal To) - Syntax: (= num1 num2 ...) - Purpose: Checks if all numbers are equal. - Example:

(= 3 3)   ; => #t
(= 3 4)   ; => #f
(= 3 3.0) ; => #t (exact and inexact numbers can be equal)
Outputs:
#t
#f
#t

#### b. < (Less Than) - Syntax: (< num1 num2 ...) - Purpose: Checks if numbers are in increasing order. - Example:

(< 3 5)   ; => #t
(< 5 3)   ; => #f
(< 3 3)   ; => #f
Outputs:
#t
#f
#f

#### c. > (Greater Than) - Syntax: (> num1 num2 ...) - Purpose: Checks if numbers are in decreasing order. - Example:

(> 5 3)   ; => #t
(> 3 5)   ; => #f
(> 3 3)   ; => #f
Outputs:
#t
#f
#f

#### d. <= (Less Than or Equal To) - Syntax: (<= num1 num2 ...) - Purpose: Checks if numbers are in non-decreasing order. - Example:

(<= 3 5)  ; => #t
(<= 5 5)  ; => #t
(<= 5 3)  ; => #f
Outputs:
#t
#t
#f

#### e. >= (Greater Than or Equal To) - Syntax: (>= num1 num2 ...) - Purpose: Checks if numbers are in non-increasing order. - Example:

(>= 5 3)  ; => #t
(>= 5 5)  ; => #t
(>= 3 5)  ; => #f
Outputs:
#t
#t
#f

#### f. zero? - Syntax: (zero? num) - Purpose: Checks if a number is zero. - Example:

(zero? 0) ; => #t
(zero? 1) ; => #f
Outputs:
#t
#f

#### g. positive? - Syntax: (positive? num) - Purpose: Checks if a number is greater than zero. - Example:

(positive? 5) ; => #t
(positive? -3); => #f
Outputs:
#t
#f

#### h. negative? - Syntax: (negative? num) - Purpose: Checks if a number is less than zero. - Example:

(negative? -3); => #t
(negative? 5) ; => #f
Outputs:
#t
#f

#### i. even? - Syntax: (even? num) - Purpose: Checks if a number is even. - Example:

(even? 4) ; => #t
(even? 5) ; => #f
Outputs:
#t
#f

#### j. odd? - Syntax: (odd? num) - Purpose: Checks if a number is odd. - Example:

(odd? 5) ; => #t
(odd? 4) ; => #f
Outputs:
#t
#f


4. Combining not with Predicates

You can use not to negate the result of a predicate function.

#### Examples:

(not (= 3 4)) ; => #t (because (= 3 4) is #f)
(not (zero? 0)); => #f (because (zero? 0) is #t)
(not (even? 5)); => #t (because (even? 5) is #f)

Outputs:

#t
#f
#t


5. Extended Example: Combining Predicates

Here’s a function that checks if a number is positive and even:

(define (positive-even? n)
  (and (positive? n) (even? n)))

(positive-even? 4) ; => #t
(positive-even? -4); => #f
(positive-even? 5) ; => #f

Outputs:

#t
#f
#f


6. Advanced: Using Predicates in Higher-Order Functions

You can use predicates with higher-order functions like filter to process lists.

#### Example:

(define numbers '(1 2 3 4 5 6 7 8 9 10))
(filter even? numbers) ; => (2 4 6 8 10)
(filter positive? numbers) ; => (1 2 3 4 5 6 7 8 9 10)
(filter (lambda (x) (not (zero? x))) numbers) ; => (1 2 3 4 5 6 7 8 9 10)

Outputs:

(2 4 6 8 10)
(1 2 3 4 5 6 7 8 9 10)
(1 2 3 4 5 6 7 8 9 10)


Output

The statement that "Scheme output functions aren't used" might be referring to the fact that Scheme, as a minimalist and functional programming language, often emphasizes computational purity and avoiding side effects (like printing to the console). In functional programming, the focus is on returning values rather than performing actions like input/output (I/O), which are considered side effects.

Here’s a breakdown of what this might mean:


1. Functional Programming Philosophy

  • In pure functional programming, functions are designed to take inputs and return outputs without causing side effects (e.g., modifying state or interacting with the outside world).
  • Output functions like display, write, and newline are inherently impure because they interact with the outside world (e.g., printing to the console).
  • Scheme, being a multi-paradigm language, supports functional programming, so some programmers might avoid using output functions to adhere to a more "pure" functional style.

2. Scheme's Minimalism

  • Scheme is designed to be a minimal and elegant language. Its standard library is intentionally small, and many tasks (like complex I/O) are left to implementations or libraries.
  • Output functions are not the primary focus of the language, and some Scheme programmers might prefer to use them sparingly or only when necessary.

3. Alternative Approaches

  • Instead of directly using output functions, Scheme programmers might structure their programs to return values that can be displayed by the REPL (Read-Eval-Print Loop) or another layer of the program.
  • For example, in a Scheme REPL, you can simply evaluate an expression, and the result will be printed automatically:
    (+ 2 3)
    
    Output:
    5
    
  • This avoids the need for explicit output functions like display or write.

4. Educational Context

  • If the text you read is from an educational resource, it might be emphasizing the importance of understanding Scheme's core concepts (e.g., recursion, lambda expressions, and higher-order functions) rather than focusing on I/O, which is considered more of a practical concern.

5. When Output Functions Are Used

  • Despite the emphasis on purity, output functions are still useful in real-world programming, especially for debugging, logging, or interacting with users.
  • For example:
    (define (factorial n)
      (if (= n 0)
          1
          (* n (factorial (- n 1)))))
    
    (display "The factorial of 5 is: ")
    (display (factorial 5))
    (newline)
    
    Output:
    The factorial of 5 is: 120