Asi concatenative
Forth/Factor/Joy: stack-based concatenative programming where composition replaces application.
install
source · Clone the upstream repo
git clone https://github.com/plurigrid/asi
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/plurigrid/asi "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/asi/skills/concatenative" ~/.claude/skills/plurigrid-asi-concatenative && rm -rf "$T"
manifest:
plugins/asi/skills/concatenative/SKILL.mdsource content
Concatenative Programming Skill
"Programs are composed by concatenation. The stack is the only state."
Core Concept
In concatenative languages:
- Stack is the implicit data structure
- Words (functions) transform the stack
- Composition = Concatenation —
means "do f, then g"f g - No variables (mostly) — data flows through stack
3 4 + \ Push 3, push 4, add → 7 on stack dup * \ Duplicate top, multiply → 49
Why It's Strange
- No application —
becomesf(x)x f - No variables — use stack manipulation
- Point-free by default — everything is tacit
- Quotations — code as data
[ ... ] - Extreme composability — every word combines freely
Forth Basics
\ Comments start with backslash 3 4 + \ → 7 10 3 / \ → 3 (integer division) 1 2 3 + * \ 1 * (2 + 3) = 5 \ Stack manipulation DUP \ a → a a DROP \ a b → a SWAP \ a b → b a OVER \ a b → a b a ROT \ a b c → b c a \ Defining words : SQUARE DUP * ; 5 SQUARE \ → 25 : CUBE DUP DUP * * ; 3 CUBE \ → 27
Factor (Modern Forth)
! Stack effect declarations : square ( n -- n^2 ) dup * ; : cube ( n -- n^3 ) dup dup * * ; ! Quotations (anonymous functions) { 1 2 3 } [ 2 * ] map ! → { 2 4 6 } { 1 2 3 4 } [ even? ] filter ! → { 2 4 } ! Cleave combinator (apply multiple quotations) 5 [ 1 + ] [ 2 * ] bi ! → 6 10 ! Spread combinator 1 2 [ 1 + ] [ 2 * ] bi* ! → 2 4
Joy (Functional Concatenative)
# No mutable state, pure functional # Quotations are first-class [dup *] square define 5 square # → 25 # Combinators [1 2 3] [2 *] map # → [2 4 6] [1 2 3 4 5] 0 [+] fold # → 15 # Recursion via Y combinator [dup 0 = [pop 1] [dup 1 - factorial *] ifte] factorial define 5 factorial # → 120
Stack Effect Notation
( before -- after ) dup ( a -- a a ) drop ( a -- ) swap ( a b -- b a ) over ( a b -- a b a ) rot ( a b c -- b c a ) + ( a b -- a+b )
Quotations and Combinators
| Combinator | Stack Effect | Meaning |
|---|---|---|
| | Execute quotation |
| | Run quot, restore x |
| | Run quot, keep x |
| | |
| | |
| | Apply all to x |
Point-Free Style
! Instead of: : sum-of-squares-bad ( seq -- n ) 0 swap [ sq + ] each ; ! Point-free: : sum-of-squares ( seq -- n ) [ sq ] map sum ; ! Even more point-free: : sum-of-squares ( seq -- n ) [ sq ] [ + ] map-reduce ;
Implementation
class ConcatVM: def __init__(self): self.stack = [] self.words = { '+': self.add, '*': self.mul, 'dup': self.dup, 'drop': self.drop, 'swap': self.swap, } def push(self, val): self.stack.append(val) def pop(self): return self.stack.pop() def add(self): b, a = self.pop(), self.pop() self.push(a + b) def mul(self): b, a = self.pop(), self.pop() self.push(a * b) def dup(self): self.push(self.stack[-1]) def drop(self): self.pop() def swap(self): self.stack[-1], self.stack[-2] = self.stack[-2], self.stack[-1] def define(self, name, body): """Define new word as sequence of words.""" def new_word(): for word in body: self.run(word) self.words[name] = new_word def run(self, program): if isinstance(program, (int, float)): self.push(program) elif program in self.words: self.words[program]() else: raise ValueError(f"Unknown: {program}") # Usage vm = ConcatVM() vm.define('square', ['dup', '*']) for token in [5, 'square']: vm.run(token) print(vm.stack) # [25]
GF(3) Integration
# Trit stack with GF(3) operations class TritStack: def __init__(self): self.stack = [] # Stack of trits: -1, 0, +1 def push(self, trit): assert trit in (-1, 0, 1) self.stack.append(trit) def gf3_add(self): """( a b -- (a+b) mod 3 )""" b, a = self.stack.pop(), self.stack.pop() result = (a + b) % 3 result = result if result != 2 else -1 self.stack.append(result) def trit_sum(self): """Conservation check.""" return sum(self.stack) % 3
Categorical Semantics
Concatenative languages are Cartesian closed categories where:
- Objects = stack types
- Morphisms = stack transformations
- Composition = concatenation
- Identity = empty program
f : A → B g : B → C g ∘ f = "f g" : A → C
Languages
| Language | Era | Features |
|---|---|---|
| Forth | 1970 | Original, minimal |
| PostScript | 1982 | Graphics, stacks |
| Joy | 2001 | Pure functional |
| Factor | 2003 | Modern, typed |
| Cat | 2006 | Statically typed |
| Kitten | 2016 | Effect system |
When to Use
- Embedded systems — Forth is tiny
- DSLs — Easy to extend
- Calculators — RPN style
- Compilers — Stack machines as target
Literature
- Moore (1970) - Forth invention
- von Thun (2001) - "Joy: Forth's Functional Cousin"
- Pestov (2010) - Factor language
- Diggins (2008) - "Cat: A Typed Concatenative Language"
Related Skills
- Implementation targetstack-machines
- Point-free styletacit-programming
- Also combinator-basedrank-polymorphism
- RPNpostfix-notation
Scientific Skill Interleaving
This skill connects to the K-Dense-AI/claude-scientific-skills ecosystem:
Graph Theory
- networkx [○] via bicomodule
- Universal graph hub
Bibliography References
: 139 citations in bib.duckdbcategory-theory
Cat# Integration
This skill maps to Cat# = Comod(P) as a bicomodule in the equipment structure:
Trit: 0 (ERGODIC) Home: Prof Poly Op: ⊗ Kan Role: Adj Color: #26D826
GF(3) Naturality
The skill participates in triads satisfying:
(-1) + (0) + (+1) ≡ 0 (mod 3)
This ensures compositional coherence in the Cat# equipment structure.