lynxql 0.1.0

A parser for the Lynx declarative modeling language - a statically typed language for expressing combinatorial optimization problems
Documentation
# 🦊 Lynx Language

Lynx is a **declarative modeling language** for defining and solving **combinatorial optimization problems** using **Integer Linear Programming (ILP)**. It allows users to define types, relationships, properties, and optimization goals in a concise and expressive syntax designed specifically for logic-based, constraint-driven models.

## ✨ Key Features

* Declarative syntax — no loops, no side effects
* Strong typing with support for primitive and composite types
* Expressive constraint and logic composition using built-ins like `All`, `Any`, `AtLeast`, `Not`, etc.
* Full support for `find`, `match`, `sum`, `solve`, and other built-in functions
* ILP-compatible: all model logic must compile to a linear formulation

---

## 📦 Example

```lynx
// Demonstrates use of match to compute a value based on logic

type Hammer: bool {
  material: string,
  size: int,
  cost: float
}

type Toolbox: All {
  hammers: Any[Hammer],
  weight: int = (t: Toolbox) -> match(t, {
    Any(find((h: Hammer) -> h.material == "steel")): 10,
    Any(find((h: Hammer) -> h.material == "wood")): 7,
    _: 5
  })
}

type Size: int

type Hammer: bool {
  material: string,
  size: Size,
  cost: float
}

type Nail: bool {
  length: int,
  amount: int,
  cost: float
}

type Toolbox: All {
  hammers: AtLeast<1>[Hammer] = (_) -> find((h: Hammer) -> h.size >= 8),
  nails: Any[Nail]?,
  boxType: BoxType
}

type Carpenter: All {
  name: string,
  age: int,
  workable: bool = (c: Carpenter) -> c.age >= 18,
  toolbox: Toolbox,
  salery: float = (c: Carpenter) ->
    +sum(c.toolbox.hammers.cost)
    +sum(c.toolbox.nails, 0.0)
    -20000.0
}

Hammer hammer1 { material: "steel", size: 10 }
Nail nail1 { length: 5, amount: 100 }

Carpenter john {
  name: "John Doe",
  age: 30,
  workable: true,
  toolbox: Toolbox {
    hammers: AtLeast<1> { hammer1 },
    nails: Any { nail1 },
    boxType: BoxType { width: 30, height: 20, depth: 15 }
  }
}

a_solution = solve(john, { nail1: 1.0 }, { Not { hammer1 } })
```

---

## 🧠 Language Concepts

### 🧱 Type Declarations

* **Primitive types** (e.g., `bool`, `int`, `float`) can have additional metadata.
* **Composite types** use logical constructors like `All`, `Any`, `Exactly`, etc. to express relationship constraints.

```lynx
type Product: All {
  options: Exactly<1>[Option],
  price: float = (p: Product) -> sum(p.options.price)
}
```

### 🔗 Relationships

Relationships are declared with logical and cardinality operators:

* `All[T]` – all connected instances must be satisfied
* `Any[T]` – at least one must be satisfied
* `Exactly<N>[T]` – exactly N instances must be selected
* Optional relationships use `?` after the type (e.g. `Any[Nail]?`)

### 🪮 Computed Properties

Properties can be computed using pure, side-effect-free lambda expressions:

```lynx
cost: float = (t: Toolbox) -> sum(t.hammers.cost)
```

### 🔍 Find & Filter

Use `find((x: Type) -> condition)` to dynamically match instances:

```lynx
find((n: Nail) -> n.length >= 10)
```

### 🧲 Match & Logic

Use `match` for piecewise logic:

```lynx
weight: int = match(t, {
  Any(find((h: Hammer) -> h.material == "steel")): 10,
  Any(find((h: Hammer) -> h.material == "wood")): 7,
  _: 5
})
```

### 🚀 Solving

The `solve` function initiates optimization over a variable with:

* a weighted objective
* a set of constraints

```lynx
solve(john, { nail1: 1.0 }, { Not { hammer1 } })
```

---

## 📜 Design Constraints

Lynx compiles to **Integer Linear Programs**, which means:

* ❌ No loops
* ❌ No recursion
* ❌ No nonlinear math (e.g. `x * y`, `x / y`)
* ✅ All functions must return **linear-compatible** results
* ✅ All expressions are **deterministic and pure**

---

## 🔧 Built-in Functions

| Function         | Description                                         |
| ---------------- | --------------------------------------------------- |
| `solve(...)`     | Optimize an instance with objective and constraints |
| `find(...)`      | Select instances based on filter                    |
| `sum(...)`       | Add numeric values over a collection                |
| `propagate(...)` | Forward-evaluate logical implications               |
| `match(...)`     | Piecewise logic mapping                             |
| `first(...)`     | Get the first element from a list                   |

---

## 📃 File Format

Lynx files use the `.lynx` extension. The parser supports:

* Single-line comments: `// comment`
* Multi-line comments: `/* block comment */`

---

## 📚 Learn More

* [Language Reference (WIP)]./docs/spec.md
* [Getting Started]./examples/
* [Integration with ILP Solvers]./docs/solver.md

---

## 💠 Roadmap

* [ ] Static linearity checker
* [ ] VSCode syntax extension
* [ ] Type and shape inference
* [ ] Partial evaluation and result caching