R7RS Compatibility

Sigil implements most of R7RS Small, with practical extensions. This page lists what works, what works with differences, and what is missing, as of Sigil 0.22.8.

Where R7RS Names Live

Sigil does not provide the (scheme ...) library names: (import (scheme base)) fails with "library not found". The R7RS procedures live in Sigil's own modules:

  • (sigil core), which every program and library sees without an import, has most of (scheme base), (scheme case-lambda), (scheme char), (scheme lazy) and (scheme write).
  • (sigil io) has the port procedures that read and write characters, strings, bytes and bytevectors, string and bytevector ports, and file ports.
  • (sigil math) has (scheme inexact): sqrt, exp, log, the trigonometric functions, finite?, infinite? and nan?. It also re-exports the (scheme base) math procedures that core has, such as floor and quotient.
  • (sigil string) has the case-insensitive string-ci comparisons.
  • (sigil process), (sigil time) and (sigil fs) have the process-context, time and file-system procedures.

Tables on this page say "in (sigil io)" and so on where a name is not in core.

R7RS Libraries

LibraryStatusNotes
(scheme base)Mostly supportedGaps are listed in the tables below
(scheme case-lambda)Complete
(scheme char)Partialchar-alphabetic?, char-numeric?, char-whitespace? and digit-value are ASCII-only; comparisons take exactly two arguments; string-ci comparisons are in (sigil string)
(scheme complex)Not providedSigil has no complex numbers
(scheme cxr)PartialOnly caadr, cadar, caddr, cdadr, cdddr and cadddr of the 24
(scheme eval)Partialeval works; environment is missing
(scheme file)Mostly supportedIn (sigil io) and (sigil fs); with-input-from-file and with-output-to-file do not redirect the current ports
(scheme inexact)CompleteIn (sigil math)
(scheme lazy)Complete
(scheme load)Complete
(scheme process-context)PartialIn (sigil process); get-environment-variable is missing (use getenv); exit and emergency-exit treat #f as success; exit does not run dynamic-wind after thunks
(scheme read)Completeread is in (sigil io)
(scheme time)CompleteIn (sigil time)
(scheme write)Mostly supportedwrite-shared and write-simple work; write prints floats with 6 digits and labels shared structure that has no cycle (see the notes under I/O)
(scheme r5rs)Not provided

Import Modifiers

All R7RS import set modifiers are supported in both define-library and top-level import forms:

ModifierDescription
(only <import-set> <id> ...)Import only the listed identifiers
(except <import-set> <id> ...)Import all except the listed identifiers
(prefix <import-set> <prefix>)Add a prefix to all imported names
(rename <import-set> (<old> <new>) ...)Rename specific identifiers

Modifiers compose through nesting, e.g. (prefix (only (sigil math) sqrt exp) m:).

Intentionally Omitted

Sigil prioritizes practical utility over numeric tower completeness:

No Exact Rationals

Sigil has integers (fixnums and bignums) and floating-point numbers, but no rational number type:

;; Other Schemes:
(/ 1 3)  ; => 1/3 (exact rational)

;; Sigil:
(/ 1 3)  ; => 0.333... (inexact float)

numerator, denominator and rationalize work on floats and return inexact results for fractional values.

No Complex Numbers

The (scheme complex) library is not provided. complex? and real? are the same as number?.

No R5RS Compatibility Library

The (scheme r5rs) library is not provided. The R5RS names exact->inexact and inexact->exact are in core.

(scheme base) Coverage

Control Flow

FeatureStatus
if, and, or, when, unless, beginSupported
condPartial: a clause with only a test returns an undefined value instead of the test's value
casePartial: => in a clause is not supported
let, let*, letrecSupported
letrec*Partial: a lambda that refers to a later binding fails, as with let*
doPartial: a binding without a step fails to expand
call/cc, call-with-current-continuationSupported. Two call/cc forms in one expression whose receivers both return normally give a wrong result
valuesSupported
call-with-valuesPartial: a native procedure as the producer raises "apply: not a procedure"
let-values, let*-values, define-valuesPartial: proper formals only; dotted and single-symbol formals fail to expand
guard, raise, raise-continuableSupported
with-exception-handlerPartial: when the handler returns from a non-continuable raise, raise returns the handler's value instead of raising a secondary exception
dynamic-windSupported
cond-expandPartial: (and ...) with more than one requirement, (or ...) and (and) take the else branch
syntax-errorPartial: the error happens at run time as "call: not a procedure", not at expansion
featuresSupported

Procedures

FeatureStatus
lambda, defineSupported
applySupported
map, for-each (multi-list)Supported
make-parameterSupported
parameterizePartial: with a converter, the converter is applied again when the outer value is restored

Numeric

FeatureStatus
+, -, *, /Supported
=, <, >, <=, >=Supported
abs, remainder, moduloSupported
quotient, gcd, lcmPartial: they reject inexact integers such as 7.0
floor, ceiling, truncateSupported
roundPartial: rounds halves away from zero ((round 2.5) is 3.0); R7RS rounds halves to even
floor/, floor-quotient, floor-remainderSupported
truncate/, truncate-quotient, truncate-remainderSupported
max, minPartial: no inexact contagion ((max 3 2.0) is 3)
expt, square, exact-integer-sqrtSupported
exact, inexact, exact?, inexact?, exact-integer?Supported
number?, complex?, real?, rational?Supported
integer?Supported
numerator, denominator, rationalizeSupported, with inexact results for fractional values
sqrt, exp, log, sin, cos, tan, asin, acos, atanSupported, in (sigil math)
number->stringPartial: a float with no fractional part loses its .0 ((number->string 1.0) is "1")
string->numberPartial: radix prefixes are not parsed ((string->number "#xff") is #f)

Lists and Pairs

FeatureStatus
cons, car, cdr, set-car!, set-cdr!Supported
pair?, null?, list?Supported
list, make-list, lengthSupported
append, reverse, list-tail, list-refSupported
list-set!, list-copySupported
memq, memv, assq, assvSupported
member, assocPartial: the three-argument form with a comparison procedure is not supported

Booleans and Symbols

FeatureStatus
not, boolean?, boolean=?Supported
symbol?, symbol=?Supported
symbol->string, string->symbolSupported

Strings

FeatureStatus
string, make-string, string-lengthSupported
string-ref, string-set!Supported
string<?, string<=?, string>?, string>=?Supported
string=?Partial: exactly two arguments
string-upcase, string-downcase, string-foldcaseSupported
string-append, substringSupported
string->listPartial: no start and end arguments
list->stringSupported
string-copy, string-copy!Supported
string-fill!Supported
string-map, string-for-eachPartial: one string only
vector->string, string->vectorSupported

Vectors

FeatureStatus
vector, make-vector, vector-lengthSupported
vector-ref, vector-set!Supported
vector->list, list->vectorSupported
vector-copy, vector-copy!, vector-appendSupported
vector-fill!Supported
vector-map, vector-for-eachPartial: one vector only

Bytevectors

FeatureStatus
bytevector?, make-bytevector, bytevectorSupported
bytevector-lengthSupported
bytevector-u8-ref, bytevector-u8-set!Supported
bytevector-copy, bytevector-copy!Supported
bytevector-appendSupported
utf8->string, string->utf8Supported, in (sigil io)

Error Objects

FeatureStatus
errorSupported
error-object?Supported
error-object-messageSupported
error-object-irritantsSupported
error-object-typeSupported
file-error?, read-error?Partial: both return #f for the errors that failing file opens and read raise

I/O

FeatureStatus
read-char, peek-char, write-charSupported, in (sigil io)
read-line, read-stringSupported, in (sigil io)
read-u8, peek-u8, write-u8Supported, in (sigil io)
read-bytevector, read-bytevector!Supported, in (sigil io)
write-string, write-bytevectorPartial, in (sigil io): no start and end arguments
char-ready?, u8-ready?Supported, in (sigil io)
write, display, newlineSupported; see the notes on write below
current-input-port, current-output-port, current-error-portSupported
open-input-file, open-output-fileSupported, in (sigil io)
close-port, close-input-port, close-output-portSupported
call-with-portSupported
open-output-string, get-output-stringSupported
open-input-stringSupported, in (sigil io)
open-input-bytevector, open-output-bytevector, get-output-bytevectorSupported, in (sigil io)
input-port?, output-port?, textual-port?, binary-port?, port?Supported
input-port-open?, output-port-open?Supported
eof-object, eof-object?Supported
flush-output-portSupported, in (sigil io)

Notes on write:

  • It prints floats with 6 significant digits ((write (/ 1.0 3)) prints 0.333333), so a written float may not read back as the same number. number->string keeps full precision.
  • It uses datum labels for shared structure even when there is no cycle: a list holding the same sublist twice prints as (#0=(1 2) #0#). write-simple prints no labels.
  • It writes printable non-ASCII text as itself, so (write "λ") prints "λ". Control characters and invisible formatting characters (zero-width spaces, bidi controls, the byte order mark) print as one escape per character, such as \x1B; or \x202E;, and a byte that is not valid UTF-8 as \x<byte>;, which reads back as the character with that number. Everything else write prints for a string reads back as the same string. Before 0.22.13 it wrote each UTF-8 byte as \xHH with no ;, which read rejected.
  • #\λ reads as one character; a non-ASCII character is written as #\x3BB.

Records

FeatureStatus
define-record-typeNot implemented; (sigil record) has Sigil's record syntax

Macros

FeatureStatus
define-syntax, syntax-rulesSupported
Procedural macros (lambda transformers)Supported
let-syntax, letrec-syntaxNot implemented

(scheme char) Coverage

FeatureStatus
char?Supported
char=?, char<?, char>?, char<=?, char>=?Partial: exactly two arguments
char->integer, integer->charSupported
char-alphabetic?, char-numeric?, char-whitespace?Partial: ASCII only ((char-alphabetic? #\λ) is #f, and a no-break space is not whitespace)
char-upper-case?, char-lower-case?Supported
char-upcase, char-downcase, char-foldcaseSupported
char-ci=?, char-ci<?, char-ci>?, char-ci<=?, char-ci>=?Partial: exactly two arguments
digit-valuePartial: ASCII digits only
string-upcase, string-downcase, string-foldcaseSupported
string-ci=?, string-ci<?, string-ci>?, string-ci<=?, string-ci>=?Partial, in (sigil string): exactly two arguments

Feature Identifiers

The features procedure returns a list of supported feature identifiers for use with cond-expand:

(features)
; => (r7rs sigil linux posix unix x86-64 lp64 64bit little-endian)

Available features:

  • r7rs - R7RS compliance
  • sigil - Sigil implementation
  • Platform: linux, darwin, windows, freebsd, openbsd, netbsd
  • POSIX: posix, unix (on Unix-like systems)
  • Architecture: x86-64, aarch64, arm, i386, riscv
  • Data model: ilp32, lp64
  • Word size: 32bit, 64bit
  • Endianness: little-endian, big-endian

Sigil Extensions

Sigil provides additional features beyond R7RS:

Pattern Matching

(import (sigil match))

(match value
  ((a b c) (list a b c))
  ((x . rest) rest)
  (_ 'default))

Keywords

Keyword arguments in procedures:

(define (greet name: "World" times: 1)
  (do ((i 0 (+ i 1)))
      ((= i times))
    (display "Hello, ")
    (display name)
    (newline)))

(greet name: "Sigil" times: 3)

Additional Modules

  • (sigil core) - Extended list operations, filter-map, fold-left, etc.
  • (sigil json) - JSON parsing and generation
  • (sigil http) - HTTP client and server
  • (sigil socket) - TCP/UDP networking
  • (sigil process) - Process spawning
  • (sigil path) - Path manipulation
  • (sigil fs) - File system operations
  • (sigil time) - Date and time
  • (sigil channels) - CSP-style concurrency

See the Library Reference for complete documentation.

Porting from Other Schemes

Replace (scheme ...) imports with Sigil modules. Most code needs no import at all for (scheme base), because (sigil core) is always available; add (sigil io), (sigil math) or (sigil string) for the names listed above.

From Guile

Guile modules map directly:

;; Guile
(use-modules (ice-9 match))

;; Sigil
(import (sigil match))

From Racket

Racket's #lang is not supported. Convert to standard module syntax:

;; Racket
#lang racket
(define (foo x) x)

;; Sigil
(define-library (my-module)
  (export foo)
  (import (sigil core))
  (begin
    (define (foo x) x)))

From Chicken

SRFI libraries are not bundled: (import (srfi srfi-1)) fails with "library not found". Core has list procedures with SRFI-1 names, but some differ from SRFI-1:

  • fold calls its procedure as (proc acc elem), so (fold cons '() '(1 2 3)) gives (((() . 1) . 2) . 3).
  • remove takes an item to remove, not a predicate.
  • any returns #t, not the true value its predicate returned.