Scheme

Scheme is derivate of Lisp. A programming language with even less syntax than Tcl itself. (but special forms and the like...? RS)

Scheme is a lexically-scoped, block structured, dynamically typed, mostly functional language. It is a variant of Lisp. It has first-class procedures with block structure and indefinite extent. Parameter passing is by value, but all values are references. It has first-class continuations to allow the construction of new control abstractions. It has lexically-scoped ("hygienic") macros to allow definition of of new syntactic forms, or redefinition of old ones.
An Introduction to Scheme and its Implementation

See Also

Biglook
Muddy Scheme
a Scheme implementation in Tcl
Playing Scheme
Tcl and LISP
Playing LISP
Serial summing
Cameron Laird's personal notes on Scheme
tcl-scheme, by Ian Bicking
a translation of Tcl into Guile/Scheme

Reference

Structure and Interpretation of Computer programs, by Harold Abelson, Gerald Jay Sussman, Julie Sussman
Monadic Programming in Scheme

Tools

PS/Tk
Portable Scheme interface to Tk
Chicken/Tk, by Wolf-Dieter Busch
An interface to Tk, based on scheme_wish
scheme_wish, by Sven Hartrumpf
a portable interface between Scheme and Tcl/Tk
Scheme Tk
a free R4RS Scheme interpreter that can access Tk. Concretely, it can be seen as the standard Tk package where Tcl has been replaced by a Scheme interpreter
Scheme Widget Library
a graphics package for Chez Scheme , based on Tk

Description

wdb: I strongly disagree that Scheme has less syntax than Tcl! Reason: the symbols have a value per se. Tcl has no symbols as $varname is just a shortcut for [set varname] where varname is just a constant, and the procedure addressed by set carries all the semantics. In Tcl, the command list unknown returns unknown because it is a constant. In Scheme, (list unknown) throws an error unless a symbol unknown is defined. If you want to list an unknown symbol, indeed, you need the special form (quote unknown) resp. its shortcut 'unknown.

  • In Lisp, the special form quote is essential.
  • In Tcl, it is not necessary as it can be defined as a regular procedure as follows:
proc quote x {
    set x
}

(Thank you, RS, for the hint with the combinator Identity!)


One interesting difference is that setting of (only global?) variables and function definition both are done with define, which creates a lambda if its first element is a list. Just for experimenting, here's how to have that in Tcl:

proc define {what how} {
    if {[llength $what] == 1} {
         uplevel 1 set $what [list $how]
    } else {
         proc [lindex $what 0] [lrange $what 1 end] $how
    }
}
% define x 42
42
% define {+ x y} {expr {$x+$y}}
% + $x $x
84

This prevents us from having spaces in variable names (not a big problem), but presents the function name and arguments in one list, similar to how it will later be called - people sometimes wonder why we define proc foo {x y} {..} but call it foo $x $y...


silas 2018-11-14: LISP has the quote operator ('), as described above, but also has the backquote operator (`) that does what (in Scheme parlance) is called quasi-quotation. It will not eval anything unless lists followed by commas. Take the following Scheme code as an example:

(define (nl) (display "\n"))

(define x 10)
(define v '(display x))
(display v)
(nl)
(eval v)
(nl)

(define a 20)
(define y `(display ,(+ a 10)))
(display y)
(nl)
(eval y)
(nl)

; Output is:
; (display x)
; 10
; (display 30)
; 30

In Tcl I've stumbled upon situations where I needed something similar. Usually people use eval "..." and escape \$ and [ when don't want it to be evaluated, but it can lead to more or less unreadable code. I wrote a small method called xset that works just like set, but replaces variables that start with @:

proc xset {var body} {
    # Look for own @ identifiers in $body
    set my_identifiers [regexp -inline -all {@[[:alpha:]]+} $body]
    set my_identifiers [lsort -unique $my_identifiers]
    set map_list [list]

    # Builds the map_list variable
    foreach my_ident $my_identifiers {
        set ident [string map [list "@" ""] $my_ident]
        upvar 1 $ident x

        # If upvar'ed variable does not exist, raise an error.
        if {[catch {lappend map_list $my_ident $x}]} {
            set raw_name [string map [list "@" ""] $my_ident]
            return -code error \
                   -errorinfo "can't read $raw_name: no such variable"
        }
    }

    # Make substitutions, set and return $body.
    upvar 1 $var x
    set body [string map $map_list $body]
    set x $body
    return $body
}

And example to that would be:

set one 1
xset test {
    set one "test"
    set a $one
    set b @one
}
puts $test

# outputs:
# set one "test"
# set a $one
# set b 1

How would you implement quasi-quotation in Tcl?