From e04af86491d97b297406cc4cd0d77fbbfc3a94c4 Mon Sep 17 00:00:00 2001 From: JJ Date: Thu, 16 May 2024 17:40:34 -0700 Subject: docs: update website --- docs/index.html | 117 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 69 insertions(+), 48 deletions(-) (limited to 'docs/index.html') diff --git a/docs/index.html b/docs/index.html index 02df44f..01b238a 100644 --- a/docs/index.html +++ b/docs/index.html @@ -7,7 +7,7 @@ - + @@ -176,39 +176,55 @@
A place where I can make some bad decisions.
Puck is an experimental, memory safe, structurally typed, interface-first, imperative programming language. -It aims to be clean and succinct while performant: inspired by the syntax and metaprogramming of Nim, the error handling of Swift, the performance and safety guarantees of Rust, the async/await and comptime of Zig, and the module system of OCaml.
+It aims to be consistent and succinct while performant: inspired by the syntax and metaprogramming of Nim, the error handling of Swift, the memory management of Rust and Koka, the async/await and comptime of Zig, and the module system of OCaml.# Note: These declarations are adapted from the standard prelude.
+Example: Type Classes
+# Note: These declarations are adapted from the standard prelude.
## The Result type. Represents either success or failure.
pub type Result[T, E] = union
Okay(T)
Error(E)
-## The Err interface. Useful for dynamically dispatching errors.
-pub type Err = interface
+## The Err class. Useful for dynamically dispatching errors.
+pub type Err = class
str(Self): str
dbg(Self): str
## A Result type that uses dynamically dispatched errors.
-## The Error may be any type implementing Err.
+## The Error may be any type implementing the Err class.
pub type Result[T] = Result[T, ref Err]
-## Implements the dbg function for strings.
-## As the str function is already defined for strings,
+## Implements the `dbg` function for strings.
+## As the `str` function is already defined for strings,
## this in turn means strings now implicitly implement Err.
-pub func dbg(self: str) = "\"" & self & "\""
+pub func dbg(self: str) = "\"" & self & "\""
+
+
# Note: These declarations are adapted from the standard prelude.
+
+## Syntactic sugar for dynamic result type declarations.
+pub macro !(T: type) =
+ quote Result[`T`]
+
+## Indirect access. Propagates `Error`.
+pub macro ?[T, E](self: Result[T, E]) =
+ quote
+ match `self`
+ of Okay(x) then x
+ of Error(e) then return Error(e)
## Opens the std.tables module for unqualified use.
+## Opens the std.tables module for unqualified use.
use std.tables
-pub type Value = string
-pub type Ident = string
-pub type Expr = ref union
+pub type Value = str
+pub type Ident = str
+pub type Expr = ref union # tagged, algebraic unions
Literal(Value)
Variable(Ident)
Abstraction(param: Ident, body: Expr)
@@ -217,29 +233,50 @@ pub type Expr = ref union
then_branch: Expr, else_branch: Expr)
## Evaluate an Expr down to a Value, or return an Error.
-pub func eval(context: mut HashTable[Ident, Value], expr: Expr): Result[Value]
- match expr
- of Literal(value): Okay(value)
- of Variable(ident):
- context.get(ident)
- .err("Could not find variable {} in context!".fmt(ident))
- of Application(body, arg):
- if body of Abstraction(param, body as inner_body):
+pub func eval(context: mut Table[Ident, Value], expr: lent Expr): Value! =
+ match expr # structural pattern matching and guards are supported but not shown
+ of Literal(value) then
+ Okay(value.clone) # ownership necessitates we explicitly clone
+ of Variable(ident) then
+ context.get(ident) # whitespace is significant but flexible
+ .err("Could not find variable {} in context!"
+ .fmt(ident)) # uniform function call syntax allows arbitrary piping/chaining
+ of Application(body, arg) then
+ if body of Abstraction(param, body as inner_body) then # compact matching with if
context.set(param, context.clone.eval(arg)?)
- context.eval(inner_body)
- else:
- Error("Expected Abstraction, found body {} and argument {}".fmt(body, arg))
- of Conditional(condition, then_branch, else_branch):
- if context.clone.eval(condition)? == "true":
+ context.eval(inner_body) # all values must be handled: returns are implicit
+ else
+ Error("Expected Abstraction, found body {} and arg {}".fmt(body.clone, arg.clone))
+ of Conditional(condition, then_branch, else_branch) then
+ if context.clone.eval(condition)? == "true" then
context.eval(then_case)
- else:
+ else
context.eval(else_case)
- of _: Error("Invalid expression {}".fmt(expr))
+ of _ then Error("Invalid expression {}".fmt(expr))
...
+# The top-level module declaration can be elided if the file shares the same name.
+pub mod tables =
+ ## The Table class. Any sort of table - no matter the underlying
+ ## representation - must implement these methods.
+ pub type Table[K, V] = class
+ get(lent Self, lent K): lent V?
+ get(mut Self, lent K): mut V?
+ set(mut Self, lent K, V): V?
+ pop(mut Self, lent K): V?
+ clear(mut Self)
+ size(lent Self): uint
+ init(varargs (K, V)): Self
+
+ ...
+
+ pub mod hashtable =
+ use std.hashes
+
+ pub type HashTable[K, V] = struct
+ ...
That said: in the future, once somewhat stabilized, reasons why you would use it would be for: