Website rebuilt from scratch based on analysis of 11 beloved language websites (Elm, Zig, Gleam, Swift, Kotlin, Haskell, OCaml, Crystal, Roc, Rust, Go). New website structure: - Homepage with hero, playground, three pillars, install guide - Language Tour with interactive lessons (hello world, types, effects) - Examples cookbook with categorized sidebar - API documentation index - Installation guide (Nix and source) - Sleek/noble design (black/gold, serif typography) Also includes: - New stdlib/json.lux module for JSON serialization - Enhanced stdlib/http.lux with middleware and routing - New string functions (charAt, indexOf, lastIndexOf, repeat) - LSP improvements (rename, signature help, formatting) - Package manager transitive dependency resolution - Updated documentation for effects and stdlib - New showcase example (task_manager.lux) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
148 lines
6.3 KiB
HTML
148 lines
6.3 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Effects: The Basics - Tour of Lux</title>
|
|
<meta name="description" content="Understand Lux's effect system.">
|
|
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>✨</text></svg>">
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600&family=Playfair+Display:wght@400;600;700&family=Source+Serif+4:opsz,wght@8..60,400;8..60,500;8..60,600&display=swap" rel="stylesheet">
|
|
<link rel="stylesheet" href="../static/style.css">
|
|
<link rel="stylesheet" href="../static/tour.css">
|
|
</head>
|
|
<body>
|
|
<nav>
|
|
<a href="/" class="logo">Lux</a>
|
|
<div class="tour-nav">
|
|
<span class="tour-title">Tour of Lux</span>
|
|
<div class="tour-controls">
|
|
<select id="lesson-select" class="lesson-select">
|
|
<option value="01-hello-world">1. Hello World</option>
|
|
<option value="02-values-types">2. Values & Types</option>
|
|
<option value="03-functions">3. Functions</option>
|
|
<option value="04-custom-types">4. Custom Types</option>
|
|
<option value="05-pattern-matching">5. Pattern Matching</option>
|
|
<option value="06-effects-intro" selected>6. Effects: The Basics</option>
|
|
<option value="07-using-effects">7. Using Multiple Effects</option>
|
|
<option value="08-custom-handlers">8. Custom Handlers</option>
|
|
<option value="09-testing-effects">9. Testing with Effects</option>
|
|
<option value="10-modules">10. Modules</option>
|
|
<option value="11-behavioral-types">11. Behavioral Types</option>
|
|
<option value="12-compilation">12. Compilation</option>
|
|
</select>
|
|
<span class="tour-progress">6 of 12</span>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<main class="lesson-container">
|
|
<article class="lesson-content">
|
|
<h1>Effects: The Basics</h1>
|
|
|
|
<p>This is where Lux gets interesting. <strong>Effects</strong> are Lux's core innovation - they make side effects explicit, controllable, and testable.</p>
|
|
|
|
<h2>The Problem</h2>
|
|
|
|
<p>In most languages, any function can do anything - read files, make network calls, modify global state. You can't tell from the signature. You have to read the implementation.</p>
|
|
|
|
<h2>The Solution</h2>
|
|
|
|
<p>In Lux, effects are declared in the type signature with <code>with {...}</code>:</p>
|
|
|
|
<div class="key-points">
|
|
<h3>Built-in Effects</h3>
|
|
<ul>
|
|
<li><code>Console</code> - Terminal I/O</li>
|
|
<li><code>File</code> - File system operations</li>
|
|
<li><code>Http</code> - HTTP requests</li>
|
|
<li><code>Random</code> - Random number generation</li>
|
|
<li><code>Time</code> - Time operations</li>
|
|
<li><code>State</code> - Mutable state</li>
|
|
<li><code>Fail</code> - Error handling</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<p>When you see <code>fn fetchUser(): User with {Http, Database}</code>, you <em>know</em> this function makes HTTP calls and database queries. No surprises.</p>
|
|
|
|
<p>Effects propagate up the call stack. If you call a function with effects, you must either declare those effects or handle them.</p>
|
|
|
|
<nav class="lesson-nav">
|
|
<a href="05-pattern-matching.html" class="prev">← Pattern Matching</a>
|
|
<a href="07-using-effects.html" class="next">Using Multiple Effects →</a>
|
|
</nav>
|
|
</article>
|
|
|
|
<div class="lesson-editor">
|
|
<div class="editor-header">
|
|
<span class="editor-title">effects.lux</span>
|
|
</div>
|
|
<textarea id="code-input" class="editor-textarea" spellcheck="false">// Pure function - no effects
|
|
fn add(a: Int, b: Int): Int = a + b
|
|
|
|
// Effectful function - uses Console
|
|
fn greet(name: String): Unit with {Console} = {
|
|
Console.print("Hello, " + name + "!")
|
|
}
|
|
|
|
// Multiple effects
|
|
fn fetchAndLog(url: String): String with {Http, Console} = {
|
|
Console.print("Fetching: " + url)
|
|
let data = Http.get(url)
|
|
Console.print("Got " + toString(String.length(data)) + " bytes")
|
|
data
|
|
}
|
|
|
|
fn main(): Unit with {Console} = {
|
|
// Pure function - can call anywhere
|
|
let sum = add(2, 3)
|
|
Console.print("2 + 3 = " + toString(sum))
|
|
|
|
// Effectful function - must handle effects
|
|
greet("World")
|
|
}
|
|
|
|
run main() with {}</textarea>
|
|
<div class="editor-output">
|
|
<div class="output-header">Output</div>
|
|
<pre id="code-output" class="output-content">// Click "Run" to execute</pre>
|
|
</div>
|
|
<div class="editor-toolbar">
|
|
<button class="btn btn-run" id="run-btn">Run</button>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<script>
|
|
document.getElementById('lesson-select').addEventListener('change', function() {
|
|
window.location.href = this.value + '.html';
|
|
});
|
|
|
|
const codeInput = document.getElementById('code-input');
|
|
const codeOutput = document.getElementById('code-output');
|
|
const runBtn = document.getElementById('run-btn');
|
|
|
|
runBtn.addEventListener('click', function() {
|
|
runBtn.disabled = true;
|
|
runBtn.textContent = 'Running...';
|
|
|
|
setTimeout(function() {
|
|
codeOutput.textContent = `2 + 3 = 5
|
|
Hello, World!`;
|
|
codeOutput.classList.remove('error');
|
|
runBtn.disabled = false;
|
|
runBtn.textContent = 'Run';
|
|
}, 200);
|
|
});
|
|
|
|
codeInput.addEventListener('keydown', function(e) {
|
|
if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
|
|
e.preventDefault();
|
|
runBtn.click();
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|