键盘快捷键

使用 跳转章节

使用 S/ 在本书内搜索

使用 ? 显示帮助页面

使用 Esc 隐藏帮助页面

KSL Syntax

Overview

KSL syntax draws inspiration from the Wolfram Language and LISP. It adheres strictly to prefix notation and does not provide any infix operators.

The syntax is built around three primary constructs: basic elements, lists, and function calls.

Basic Elements

KSL defines five fundamental data types: Symbols, Atoms, Strings, Numbers, and Objects.

Symbols

Symbols act as identifiers for variables and functions.

Note: In KSL, “letters” broadly include most Unicode characters, excluding the majority of ASCII symbols and invisible control characters.

  • First character: Must be a letter or an underscore (_). Digits and punctuation marks are not allowed.
  • Subsequent characters: May contain letters, digits, underscores (_), or single quotes (').
  • Private symbols: Symbols beginning with an underscore are module-local and cannot be loaded from other files.

Examples: a, Add, _privateFunc', _你好👋'.

Atoms

Atoms are unique, constant identifiers, analogous to enumeration values.

  • Prefix: Must start with a hash symbol (#).
  • First character: Must be a letter. Digits, underscores, and punctuation marks are not permitted.
  • Subsequent characters: May contain letters, digits, underscores (_), or single quotes (').

Examples: #some'tag, #你好👋'.

Convention: The atoms #t and #f represent the boolean values true and false, respectively.

Strings

Strings are immutable sequences of characters enclosed in double quotes ("). They may span multiple lines; all whitespace, line breaks, and indentation within the quotes are preserved verbatim.

Standard escape sequences (e.g., \n) are not supported. To embed a special character, use a hash symbol (#) followed by its decimal Unicode code point.

Let[s, "Hello, world🌏,
Line breaks are directly supported.
  Leading whitespace is also preserved."];

(* Insert a newline character (Unicode code point 10) *)
Let[s', Concat[s, #10, "This appears on a new line."]];

Numbers

All numbers are represented as 64-bit floating-point values (f64). They may be written as integers, decimals, or in scientific E-notation. The integer part is mandatory; a leading decimal point (e.g., .5) is invalid.

Objects

Objects are key-value containers that represent structured data. Each object carries a type tag for identification.

Creation and Initialization

The Object function creates a new object and requires at least a type tag. Use GetType to inspect an object’s type tag. Initial data can be provided by passing a list of { key, value } pairs as the second argument.

Let[obj, Object[TypeName]];
Print[Eq[GetType[obj], #TypeName]]; (* => #t *)

Let[obj2, Object[Another, {
  { #k1, "v1" },
  { #k2, 2 }
}]];

Immutability and Updates

KSL enforces strict immutability for objects. Functions that appear to modify an object—such as Set (to add or update a property) or Delete (to remove a property)—never alter the original object. Instead, they return a new object instance with the requested change.

To retain these changes, the variable holding the object must be rebound. KSL offers two distinct rebinding mechanisms, each with different scope behavior:

  • Let (Local Shadowing): Introduces a new local binding in the current scope. This binding shadows any outer variable of the same name; the outer variable remains unchanged once the scope exits.
  • Update (Scope Updating): Modifies the existing binding of a variable in its enclosing scope. Changes made via Update persist after the current block ends.
(* Initialize an empty object *)
Let[obj, Object[MyType]];

(* 1. Using Let: Local shadowing *)
Block[
  Let[obj, Set[obj, #key1, "val1"]],
  Print[Has[obj, #key1]]  (* => #t (The local 'obj' has the key) *)
];
Print[Has[obj, #key1]];   (* => #f (The outer 'obj' remains unchanged) *)

(* 2. Using Update: Modifying the existing binding *)
Block[
  Update[obj, Set[obj, #key1, "val1"]],
  Print[Has[obj, #key1]]  (* => #t *)
];
Print[Has[obj, #key1]];   (* => #t (The outer 'obj' is now updated) *)

(* 3. Removing a property and persisting the change *)
Update[obj, Delete[obj, #key1]];

Inspection and Access

  • Printing: Displays the object’s type tag together with its keys.
  • Keys: Obtain a list of all keys using Keys[obj]. The order of keys is unspecified because objects are implemented as hash maps.
  • Values: Retrieve the value associated with a specific key using Get[obj, #key].

Lists

Lists are ordered, heterogeneous sequences enclosed in curly braces ({ }). Elements are separated by commas.

{ 1, "2", #a3 }        (* A valid list *)
{ 1, 2, { 3, { 4 } } } (* A nested list *)

Convention: Functions that can fail often return a list whose first element is a status atom indicating success or failure.

Function Calls

Syntax

KSL uses prefix notation exclusively. A function name is followed by a comma-separated list of arguments enclosed in square brackets ([]). Functions that take no arguments still require empty brackets.

FunctionName[arg1, arg2]

Conventions

Function names are symbols. Built-in functions typically begin with an uppercase letter.

Anonymous Functions

Anonymous functions are created using Fun. They can be invoked immediately or bound to a symbol (the standard way to define named functions).

(* Invoke directly *)
Fun[{ n }, Add[n, 1]][2]; (* => 3 *)

(* Bind to a symbol *)
Let[add1, Fun[{ n }, Add[n, 1]]];
add1[3]; (* => 4 *)