No description
Find a file
2026-01-07 01:13:25 -05:00
src add thunk syntax 2026-01-07 01:13:25 -05:00
.gitignore initial 2025-12-31 23:48:33 -05:00
Cargo.lock mvp, buggy evaluation 2026-01-07 00:26:18 -05:00
Cargo.toml mvp, buggy evaluation 2026-01-07 00:26:18 -05:00
README.md add more parser tests 2026-01-02 23:56:42 -05:00

puyo 3 (this time it's nameful)

semantics

single-threaded, dynamically-typed (because lol), multiple named returns by default, pass-by-value

functions take and return a map ALWAYS

Values:

  • function
  • number (f64)
  • map (HashMap<Symbol, >)

examples

double x = x * 2

double = fn([x] [x]) (
    ^x := x * 2;
);

apply f x = f x

;; same as apply = fn([f x] [x]) ( ... )
fn apply([f x] [x]) (
    ^x := f x;
);

;; f would have to be like fn([a] [a]) ( ... )
(define (make-counter)
  (let ([i 0])
    (lambda ()
      (set! i (+ i 1))
      i)))
fn make_counter([] [inc]) (
    i := 0;
    ^inc := fn([] [i]) (
        i := i + 1;
        ^i := i;
    );

    ;; or fn ^inc(...)
)

desat hsla = { hsla with s := hsla.s / 2 }

;; omitting the return means it's the same
fn desat([h s l a]) (
    ^s := ^s / 2;
)

compose f g x = f (g x)

fn compose([f g x] [x]) (
    ^x := g x;
    ^x := f x;
)

f := fn([x]) (^x := x + 2;);
g := fn([x]) (^x := x * 3;);
f2 := f;

compose f g x == (((compose f) g) x) == compose {f: f2, g} x == compose {x} f g

id x = x

fn id([x]) ()

"Maps" should really just be blocks

foo := 3;
{ 
   x := 42;
   ^twice_x := x * 2;
   ^thrice_x := x * 3;
   ^foo;
}

becomes

{
    "twice_x": 84,
    "thrice_x": 126,
    // ^foo as a statement behaves like ^foo := foo, so we get that nice record field punning
    "foo": 3,
}