Tools: I Built a Programming Language Where think Is a Keyword
Source: Dev.to
We write if, for, and return every day without a second thought. These are the primitives of computation — the building blocks we use to tell machines what to do. But we're in a new era now. AI isn't a service you call occasionally — it's becoming a fundamental computing primitive. So why are we still using it like this? const response = await anthropic.messages.create({ model: "claude-opus-4-6", max_tokens: 1024, messages: [{ role: "user", content: "Analyze the sentiment of: " + text }], }); const result = JSON.parse(response.content[0].text); // hope it's the right shape... API boilerplate. Manual prompt construction. Untyped JSON parsing. Praying the response matches what you expected. What if instead, you could just write: let sentiment = think("Analyze the sentiment of this review") That's why I built ThinkLang — an open-source, AI-native programming language where think is a keyword. ThinkLang is a transpiler. You write .tl files, and the compiler turns them into TypeScript that calls an LLM runtime. The language has its own parser (PEG grammar), type checker, code generator, LSP server, VS Code extension, testing framework, and CLI. The compilation pipeline: parse → resolve imports → type check → code generate → execute. The core idea is simple: AI should be a language-level primitive, not a library call. The Basics: think, infer, reason ThinkLang has three AI primitives built into the language: The primary primitive. Give it a type and a prompt, and it returns structured, type-safe output. type MovieReview { title: string rating: int pros: string[] cons: string[] verdict: string } let review = think("Review the movie Inception") print(review.title) // type-safe access print(review.rating) // guaranteed to be an int The compiler turns your type declaration into a JSON schema that constrains the LLM's output. The AI cannot return anything that violates your type. No parsing. No validation. No hoping. Lightweight inference on existing values — when you already have data and want the AI to derive something from it. type Category { label: string confidence: float } let data = "The patient presents with a persistent cough and fever" let category = infer(data) Multi-step reasoning with explicit goals and steps: type Analysis { findings: string[] recommendation: string risk_level: string } let analysis = reason { goal: "Evaluate this investment opportunity" steps: 1. "Analyze the financial fundamentals" 2. "Assess market conditions and competition" 3. "Evaluate risk factors" 4. "Form a final recommendation" with context: { portfolio, market_data } } This compiles into a structured chain-of-thought prompt. The AI follows your steps explicitly rather than reasoning however it wants. Confidence as a Language Concept Here's something most AI wrappers get wrong: they treat every AI response as equally certain. But AI outputs have varying levels of confidence, and your code should reflect that. ThinkLang has Confident: type Diagnosis { condition: string severity: string } let result = think>("Diagnose based on these symptoms") print(result.value) // the actual diagnosis print(result.confidence) // 0.0 to 1.0 print(result.reasoning) // why the AI is this confident And the uncertain modifier forces you to handle uncertainty explicitly: uncertain let diagnosis = think>("Diagnose this") // This won't compile: // print(diagnosis.value) // You must explicitly unwrap: let safe = diagnosis.expect(0.8) // throws if confidence < 0.8 let fallback = diagnosis.or(default_val) // use fallback if low confidence let raw = diagnosis.unwrap() // explicit "I accept the risk" The compiler enforces this. You can't silently ignore uncertainty — you have to make a conscious decision about how to handle it. What if the AI returns something that's technically the right type but semantically wrong? A summary that's too long. A response that contains placeholder text. A rating that's out of range. Guards are declarative validation rules with automatic retry: let summary = think("Summarize this article") guard { length: 50..200 contains_none: ["TODO", "placeholder", "as an AI"] } on_fail: retry(3) then fallback("Could not generate summary") If the output fails validation, ThinkLang automatically retries up to 3 times. If all retries fail, it falls back to your default. No manual retry loops. No callback hell. You can also guard numeric fields: let review = think("Review this product") guard { rating: 1..5 length: 100..500 } on_fail: retry(2) Pattern Matching on AI Outputs ThinkLang has structural pattern matching that works beautifully with AI-generated data: type Sentiment { label: string intensity: int } let sentiment = think("Analyze: 'This is the best day ever!'") match sentiment { { label: "positive", intensity: >= 8 } => print("Extremely positive!") { label: "positive" } => print("Positive") { label: "negative", intensity: >= 8 } => print("Extremely negative") { label: "negative" } => print("Negative") _ => print("Neutral") } Pattern matching + typed AI outputs = clean, readable branching on AI results. Control exactly what data the AI sees: let user_profile = { name: "Alice", preferences: ["sci-fi", "thriller"] } let secret_key = "sk-abc123" let recommendation = think("Recommend a movie for this user") with context: user_profile without context: secret_key with context scopes data into the prompt. without context explicitly excludes sensitive data. No accidentally leaking API keys into prompts. Chain AI operations with |>: let result = "raw text input" |> think("Summarize this") |> think("Translate to French") |> think("Rate the translation quality") Readable, composable, functional-style AI pipelines. Built-in Testing Framework This is one of my favorite features. ThinkLang has a built-in test framework that understands AI: test "sentiment analysis" { let result = think("Analyze: 'I love this product'") test "summary quality" { let summary = think("Summarize the theory of relativity") assert.semantic() is an AI-powered assertion. It uses the LLM to evaluate whether the output meets qualitative criteria. No brittle string matching. AI tests are non-deterministic and cost money. ThinkLang solves both problems: # Record AI responses to snapshot files thinklang test --update-snapshots # Replay from snapshots — zero API calls, deterministic results thinklang test --replay Record once, replay forever. Your CI pipeline runs deterministic AI tests without an API key. Every AI call is automatically metered: thinklang run my-program.tl --show-cost Cost Summary: Total calls: 5 Input tokens: 2,847 Output tokens: 1,203 Estimated cost: $0.0234 You can also run thinklang cost-report to see aggregated costs across runs. No surprises on your API bill. Full Developer Ecosystem ThinkLang isn't just a language — it's a complete toolchain: I built ThinkLang as a solo developer, and I have to be honest — Claude Code was an incredible partner throughout the process. It helped me move fast, iterate on the parser grammar, debug the type checker, and ship a project of this scope. Building an entire language ecosystem (parser, checker, compiler, runtime, LSP, testing framework, VS Code extension, docs) solo would have taken significantly longer without it. AI-assisted development is real, and this project is proof of it. ThinkLang is at v0.1.1 and I have big plans: Model Agnostic Support — Right now ThinkLang uses Anthropic's Claude. The next milestone is supporting any provider: OpenAI, Gemini, Mistral, local models via Ollama, or any OpenAI-compatible endpoint. Same language, any brain. Agentic Native Coding — First-class language primitives for building AI agents. Think tool use, planning loops, and multi-agent coordination as language keywords, not library patterns. npm install -g thinklang type Greeting { message: string emoji: string } let greeting = think("Say hello to a developer trying ThinkLang for the first time") print(greeting.message) print(greeting.emoji) thinklang run hello.tl The project is MIT licensed. I'd love stars, feedback, issues, or contributions. And if you're thinking about what AI-native development looks like — let's talk. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse COMMAND_BLOCK:
assert result.label == "positive"
assert result.intensity > 5 Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
assert result.label == "positive"
assert result.intensity > 5 COMMAND_BLOCK:
assert result.label == "positive"
assert result.intensity > 5 CODE_BLOCK:
assert.semantic(summary, "explains relationship between space and time")
assert.semantic(summary, "mentions Einstein") Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
assert.semantic(summary, "explains relationship between space and time")
assert.semantic(summary, "mentions Einstein") CODE_BLOCK:
assert.semantic(summary, "explains relationship between space and time")
assert.semantic(summary, "mentions Einstein") CODE_BLOCK:
By operation: think: 3 calls, $0.0156 reason: 1 call, $0.0062 assert.semantic: 1 call, $0.0016 Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
By operation: think: 3 calls, $0.0156 reason: 1 call, $0.0062 assert.semantic: 1 call, $0.0016 CODE_BLOCK:
By operation: think: 3 calls, $0.0156 reason: 1 call, $0.0062 assert.semantic: 1 call, $0.0016 - CLI with run, compile, repl, test, and cost-report commands
- VS Code extension with syntax highlighting and 11 code snippets
- Language Server (LSP) providing real-time diagnostics, hover tooltips, code completion, go-to-definition, document symbols, and signature help
- Module system with import/export across .tl files
- Response caching — identical prompts skip the API call automatically
- 17 example programs covering every feature - PEG grammar (Peggy) for parsing
- TypeScript for the compiler, runtime, and tooling
- Zod for runtime validation
- Anthropic SDK for the AI runtime
- vscode-languageserver for the LSP
- VitePress for the documentation site - GitHub: https://github.com/eliashourany/ThinkLang
- Docs: https://thinklang.dev
- npm: https://www.npmjs.com/package/thinklang