The Core
package provides the most basic features of Crochet,
and is likely to be used by every other program in the language.
It is expected that many of the types and features introduced
here will be extended outside of the Core
package. For
example, while here we provide basic support for numeric
operations, such as arithmetic, the Mathematics
packages
will extend this support to geometry, set theory, and other
more specific areas.
Structure
Because Core
isn't focused on solving a specific problem, but
rather provide a set of building blocks that are common to many
applications, it may feel confusing and overwhelming to just look
at the types and commands defined here. So understanding how things
are structured is the first step.
Core
is divided into several categories. Each of these categories
provides basic support for some specific problem.
Numeric modelling
Core
provides a very basic support for dealing with numbers. The
root of this modelling is
numeric
, and all numeric types are
expected to extend it.
Within
numeric
we have two broader categories of types:
-
integral
is the base type for all whole numbers, such as
1234
.
There's only one integral type that
Core
provides:
integer
.
The integer type represents any whole number precisely, at the cost of
using more memory and computational power.
-
fractional
is the base type for all numbers that may contain
fractions, such as
1234.5
. There's only one fractional type that
Core
provides:
float-64bit
. This is a 64-bit IEEE-754 floating
point value—it supports representing many numbers, but as
approximations. And these approximations become less and less
precise as the number grows bigger, just so we can guarantee that
it'll use a fixed amount of memory (64-bits).
Textual modelling
Support for text is likewise very basic in
Core
. The root of this
modelling is
unsafe-arbitrary-text
, which represents any piece
of text as an opaque blob. Core then divides text further into a
trust hierarchy—granting some protection against potentially
malicious pieces of text.
Text coming from the outside should be regarded (and represented) as
untrusted-text
. This means that the piece of text is potentially
malicious, and extra care needs to be taken when using it.
Text originating from inside of the Crochet program is represented as
text
. With text that exists as a literal in the program ending
as the type
static-text
, and text that is computed while the
program executes being given the type
dynamic-text
. These are
considered
trusted pieces of text, as they originate from a known
source.
When untrusted pieces of text are involved, the only affordances that
Crochet gives are either passing them around, or combinining them. Either
through the
_ ++ _
command or the interpolation syntax (e.g.:
"here: [some-text]"
). Both result in an
interpolation
being
constructed.
Textual views
For trusted pieces of text, more affordances are given. However, because
pieces of text can have very different semantics, in order to work with
them one must first acquire a "text view". Which basically means the
semantics we expect are more explicit. Core
provides the following
views:
-
_ ascii
creates a
ascii-view
. This assumes that the
text only contains characters that are within the ASCII subset, so
even text in, e.g.: Portuguese, would likely be rejected by it. Many
pieces of text meant only for computers can be considered ASCII-only,
and some operations only make sense in that case.
-
_ lines
yields a list of text for each line in the input.
Managing trust
Whenever you have
untrusted-text
, you'll need to make it trusted
before you'll be able to operate on it. One way to do so is to use any
of the
Parsing
packages in Crochet to make sure the semantics of the
piece of text are known and fixed.
It's also possible to acquire the
untainting
capability
and use the
untaint
global binding to turn an untrusted piece of
text into a trusted piece of text. But special care needs to be given
here as many security vulnerabilities arise from allowing untrusted
text to be mixed with trusted text without full control and knowledge
of its semantics.
Logic and ordering
Crochet makes heavy use of boolean logic,
boolean
is the
root of this hierarchy, which also contains
true
and
false
as distinct singleton types.
Functions that consider ordering of values are, likewise, served
by the more restricted type
ordering
.
Handling errors
Crochet makes several distinctions about what an "error" means in a
program. For describing unsupported operations or values, the recommended
way is to model it as a Contract, through pre and post-conditions. These
more readily communicate the intent to users of the operation, as well as
to the Crochet compiler.
Sometimes, writing a good contract isn't really feasible. The remaining
unsupported operations and values can be handled by halting the program
with a panic message. The singleton type
panic
provides commands
for this.
Some errors are, however,
expected. For these cases Crochet encourages
representing them explicitly in a type hierarchy. The type
result
exists to simplify this when special semantics are not needed. A result
can either be of type
ok
, if everything went as expected, or type
error
, if something went wrong.
Collections
Core
provides very basic support for common collections. All of the
collections provided by this package are persistent—meaning that
you can only change the collection by creating a new one, and the
implementation makes this as efficient as possible.
The following collections are provided:
-
list
is a persistent vector, with support for appending and
prepending items efficiently, as well as accessing items in any order.
-
record
is an immutable, extensible record—all keys are plain
pieces of text. The current implementation does not support efficient
changes, and requires duplicating the whole record.
-
set
is a persistent set, with support for efficiently adding
items and testing if an item exists in the set.
-
map
is a persistent mapping of keys to values, with support for
arbitrary keys, and efficient adding or accessing of key/value pairs.
-
stream
is a persistent stream, currently implemented as a lazy
linked list (in
linked-stream
). Streams naturally fuse their
operations and use constant memory, but cannot be changed.
Mutable state
Core
is mostly a pure library, but it provides support for (local)
mutable state through the type
cell
. A cell is a small piece
of memory that can be changed at will, through
_ <- _
or
_ compare: _ and-set: _
. Both are guaranteed to happen
atomically.
These values in the cell can be passed along as regular immutable
values, or the cell can be passed around in read-only mode, by
constructing a
read-only-cell
. This allows others to observe
the changes in the value, but not affect it.
Traits
Core
ships with an extensive selection of basic traits, which all
have implementations for the basic types.
-
sequence
,
appendable-sequence
,
finite-sequence
,
indexed-sequence
,
modifiable-indexed-sequence
,
growable-indexed-sequence
,
sortable-sequence
,
reversible-sequence
, and
sliceable-sequence
deal with
the idea of collections of
ordered values, like lists, but unlike
sets or maps.
-
foldable-collection
,
filterable-collection
,
mappable-collection
,
chainable-collection
,
and
zippable-collection
deal with the idea of collection in
terms of
operations, rather than their concept. This is more in
line with mathematical ideas from abstract algebra, where we think
about things in more abstract terms consisting of laws and operations,
rather than their
meaning. So these generally apply to all collection
types, but may vary wildly on what you should expect—each implementation
can
re-interpret the meaning.
-
set-algebra
deals with the idea of sets, and things that can be
viewed as sets in a reasonable way.