12 Files and libraries
Use include to split one workflow across local files. Use import to reuse a versioned library from another Git repository. A ScienceLogo library is one Git repository with a main branch and a library.rkt file at its root. Importing makes its procedures and record interfaces available.
12.1 Split one workflow across files
Every included file begins with #lang sciencelogo. Its path starts at the directory of the file containing include; it must stay in the same Git repository. An included workflow file has no workflow title or import and can include more files. For example, these three paths are in one repository:
method.rkt:
#lang sciencelogo |
workflow "Pendulum trial" |
include "methods/period.rkt" |
do period 20 10 as seconds-per-swing |
print seconds-per-swing |
methods/period.rkt:
#lang sciencelogo |
include "../shared/divide.rkt" |
to period :seconds :swings [ |
do divide :seconds :swings as result |
output result |
] |
shared/divide.rkt:
#lang sciencelogo |
to divide :total :count [output :total / :count] |
The reader assembles and validates the workflow before running it. Missing files, duplicate includes, and cycles are errors. include does not create a local scope.
12.2 Library syntax
Form | Rule |
library name [ ... ] | One declaration in the root library.rkt file; contains imports, includes, procedures, and record interfaces |
import "Git URL" at "tag or commit" as alias | Directly in a library block, or at the top of an entry workflow |
include "relative/path.rkt" | Loads a file relative to the file containing this include |
do alias.procedure ... | Calls an imported procedure |
alias.Interface | Names an imported interface in construction, inheritance, is tests, and implement mappings |
The URL begins with https:// or file://. at selects a tag or full commit ID reachable from the library’s main branch, not a branch name. An alias is local to the file that declares the import. A library may import another library; a workflow imports that dependency itself if it needs to use the dependency’s procedures or interfaces directly. Importing a library never runs its procedures.
12.3 Make a small library
Create a separate directory named hello-world. Save this as its library.rkt:
#lang sciencelogo |
|
library hello-world [ |
to greeting [output "Hello, world!"] |
] |
The greeting procedure returns text. Loading the library does not print it. In that directory, initialize and tag the Git repository:
git init --initial-branch=main |
git add library.rkt |
git -c user.name="ScienceLogo example" -c user.email="example@example.invalid" commit -m "Add greeting library" |
git tag v1.0.0 |
12.4 Import and call it
Save the following investigation in another file. Replace the example file:// URL with the absolute path to your hello-world directory:
Compact
#lang sciencelogo |
|
workflow "Try a library" |
import "file:///absolute/path/to/hello-world" at "v1.0.0" as hello |
do hello.greeting as message |
print message |
Verbose
#lang sciencelogo |
|
workflow "Try a library" |
import library from "file:///absolute/path/to/hello-world" at "v1.0.0" as hello |
do hello.greeting as message |
print message |
The at value selects a tag or full commit ID reachable from main; it does not select a branch. hello is the local alias for this import. The call returns "Hello, world!" as message, and the investigation displays it. The reader resolves and validates the library before running the investigation.
12.5 Share a record interface
A library can also define a data interface, with required fields and defaults grouped inside must [...]; see Records and interfaces. In library.rkt:
Compact
#lang sciencelogo |
|
library timing [ |
interface Timing [must [duration unit = "seconds"]] |
] |
Verbose
#lang sciencelogo |
|
library timing [ |
interface Timing [must [duration set unit to "seconds"]] |
] |
After committing and tagging that repository, a workflow can import and use it:
Compact
import "file:///absolute/path/to/timing" at "v1.0.0" as timing |
interface Timed-place [extends timing.Timing must [place]] |
trial = Timed-place.[duration = 2 place = "lab"] |
trial implement timing.Timing |
Verbose
import library from "file:///absolute/path/to/timing" at "v1.0.0" as timing |
interface Timed-place [extends timing.Timing must [place]] |
set trial to Timed-place with [set duration to 2 set place to "lab"] |
trial implements timing.Timing |
The alias qualifies the interface name just as it qualifies a procedure name. Interfaces may also be placed in included library files. An included file can use include "../shared/file.rkt" from a subdirectory: the path starts at the directory containing that include, and must stay in the same repository.
For larger libraries, the root library.rkt can contain include "relative/path.rkt" declarations and imports of other libraries. Included files contain top-level to, record interface, and include declarations. A dependency alias stays inside the library that declared it; a workflow imports that dependency separately if it needs to use its procedures or interfaces directly. The library specification has the full layout and dependency rules.