The r7rs (scheme time) library, supplied as a host library.
This module is a worked example of an embeddable Schooner library
— an Elixir module that builds a Schooner.Library.t/0 via
Schooner.Host.library/1. The library is not in Schooner's
default standard registry; embedders opt in by listing it on
Schooner.Environment.new/1:
env =
Schooner.Environment.new(
libraries: [Schooner.Time.library()]
)
Schooner.eval!("(import (scheme time)) (current-second)", env)
# => 1745234567.123456The name (scheme time) is the canonical r7rs name; scripts opt in
the spec-conformant way with (import (scheme time)). Because the
library is not pre-registered, an embedder who does not list it
preserves the "default sandbox is pure" property — wall-clock
access has to be deliberately granted.
Why a host library, not a baked-in primitive
Every primitive Schooner ships in (scheme base), (scheme inexact),
and friends is pure and deterministic. Time is the first
side-effecting binding: it leaks wall-clock state into the script
and breaks reproducibility. Keeping it out of the default registry
and shipping it as a separately-opt-in host library matches the
trust model documented in Sandbox.
Authoring this as a host library — instead of as one more
Schooner.Primitives.* module — also makes it a worked reference
for embedders writing their own libraries. The shape here is the
shape recommended in Host Functions:
- A single public
library/0(orlibrary/1if the host needs to inject configuration) that returns a%Schooner.Library{}. - Internal primitive implementations follow the standard
(list(Schooner.Value.t()) -> Schooner.Value.t())ABI. - The library name is canonical (
["scheme", "time"]here), which makes it sandbox-safe — the script must(import ...)to reach it.
Copy this file as a starting point for any embeddable library that needs to expose host capabilities to Scheme.
Procedures
All three procedures are r7rs §6.13:
(current-second)— inexact seconds since the epoch. Backed by:os.system_time(:nanosecond) / 1.0e9. R7RS specifies TAI seconds; Schooner returns POSIX seconds, matching what every mainstream Scheme implementation actually does (Chibi, Racket, Guile).(current-jiffy)— exact monotonic integer. Backed by:erlang.monotonic_time/0. The absolute value is unspecified and may be negative; only differences between twocurrent-jiffycalls in the same VM are meaningful.(jiffies-per-second)— exact integer giving the resolution ofcurrent-jiffy. Backed by:erlang.convert_time_unit(1, :second, :native). Expected idiom: divide a jiffy difference by this to get seconds.
Summary
Functions
Build the (scheme time) host library. Pass to
Schooner.Environment.new/1 to make (import (scheme time))
reachable from scripts evaluated against the environment.
Primitive specs in the {name, arity, fun} shape used everywhere
in the Schooner primitive layer. Exposed so an embedder can fold
these into a larger custom library if they need a non-canonical
name or want to combine time with other host primitives.
Functions
@spec library() :: Schooner.Library.t()
Build the (scheme time) host library. Pass to
Schooner.Environment.new/1 to make (import (scheme time))
reachable from scripts evaluated against the environment.
@spec specs() :: [{binary(), 0, ([] -> Schooner.Value.t())}]
Primitive specs in the {name, arity, fun} shape used everywhere
in the Schooner primitive layer. Exposed so an embedder can fold
these into a larger custom library if they need a non-canonical
name or want to combine time with other host primitives.