Your First JSL Program¶
Welcome to JSL! This tutorial will walk you through creating your first JSL program step by step. By the end, you'll understand JSL's core concepts and be ready to build more complex applications.
What Makes JSL Different¶
JSL is unlike most programming languages you may have used before. The key insight is that code and data are the same thing - both are represented as JSON. This means:
- Your program is valid JSON that can be transmitted over networks
- Functions can be serialized and reconstructed anywhere
- Dual evaluation modes - direct interpretation or JIT compilation to stack bytecode
- Pauseable/resumable execution - programs can be suspended and continued later
- Universal compatibility - any system that handles JSON can work with JSL
Hello, World!¶
Let's start with the classic first program. JSL supports two syntax styles - JSON arrays and Lisp-style parentheses. Create a file called hello.jsl:
JSON Array Syntax¶
Lisp-Style Syntax (Human-Friendly)¶
Both are exactly equivalent! The Lisp-style is often easier to read and write, while JSON is universal for network transmission.
Now, run it from your terminal:
You should see the output:
What happened?
(host @print "Hello, JSL!")is a host interactionhostis a special form for side effects@printis the host command (@ prefix in JSON, quoted in Lisp-style)"Hello, JSL!"is the argument to print- JSL sends the print request to the host environment
How JSL Executes Your Code¶
JSL offers two execution strategies:
1. Recursive Evaluation (Default)¶
The S-expression is directly evaluated by walking the tree structure. This is the default mode and works well for most programs.
2. Stack Machine Compilation (Available on Request)¶
JSL can compile your program Just-In-Time to JPN (JSL Postfix Notation) bytecode when you need advanced features:
// Your code: ["+", 1, 2, 3]
// Compiles to JPN: [1, 2, 3, 3, "+"]
// Executes on stack machine with resumable state
The stack machine enables: - Pauseable execution - Stop after N steps and resume later - Resource limits - Control CPU/memory usage with gas metering - Distributed execution - Pause on one machine, resume on another - Debugging - Step through execution instruction by instruction
Even the paused execution state is pure JSON - maintaining JSL's core principle that everything (code, data, and even execution state) can be serialized and transmitted!
You don't need to worry about this initially - JSL handles it automatically. But it's there when you need advanced features!
Understanding Prefix Notation¶
JSL uses prefix notation - the operator comes first. Here's the same code in both syntaxes:
JSON Array Syntax¶
// Traditional: 2 + 3
["+", 2, 3]
// Traditional: 2 + 3 + 4
["+", 2, 3, 4]
// Traditional: 2 * (3 + 4)
["*", 2, ["+", 3, 4]]
Lisp-Style Syntax¶
; Traditional: 2 + 3
(+ 2 3)
; Traditional: 2 + 3 + 4
(+ 2 3 4)
; Traditional: 2 * (3 + 4)
(* 2 (+ 3 4))
The Lisp-style is often more readable, especially for complex expressions!
Variables with def¶
Use def to create variables:
[
"do",
["def", "name", "Alice"],
["def", "age", 30],
["print", "Hello,", "name", "! You are", "age", "years old."]
]
Breaking it down:
"do"executes multiple expressions in sequence["def", "name", "Alice"]creates a variable calledname["def", "age", 30]creates a variable calledage- The print statement uses the variables by referencing their names
Your First Function¶
Let's create a function to calculate the area of a circle:
[
"do",
["def", "pi", 3.14159],
["def", "circle-area",
["lambda", ["radius"],
["*", "pi", "radius", "radius"]]],
["def", "my-radius", 5],
["def", "area", ["circle-area", "my-radius"]],
["print", "Circle with radius", "my-radius", "has area", "area"]
]
Understanding lambda:
["lambda", ["radius"], ...]creates a function["radius"]is the parameter list (the function takes one argument)["*", "pi", "radius", "radius"]is the function body- The function calculates π × radius²
Working with Lists¶
Lists are fundamental in JSL. Let's explore list operations:
[
"do",
["def", "numbers", ["list", 1, 2, 3, 4, 5]],
["def", "first-number", ["first", "numbers"]],
["def", "rest-numbers", ["rest", "numbers"]],
["def", "list-length", ["length", "numbers"]],
["print", "Original list:", "numbers"],
["print", "First element:", "first-number"],
["print", "Rest of list:", "rest-numbers"],
["print", "List length:", "list-length"]
]
Higher-Order Functions¶
Now for something powerful - functions that work with other functions:
[
"do",
["def", "numbers", ["list", 1, 2, 3, 4, 5]],
// Double each number
["def", "double", ["lambda", ["x"], ["*", "x", 2]]],
["def", "doubled", ["map", "double", "numbers"]],
// Filter even numbers
["def", "is-even", ["lambda", ["n"], ["=", ["mod", "n", 2], 0]]],
["def", "evens", ["filter", "is-even", "numbers"]],
// Sum all numbers
["def", "total", ["reduce", "+", "numbers", 0]],
["print", "Original:", "numbers"],
["print", "Doubled:", "doubled"],
["print", "Evens only:", "evens"],
["print", "Sum:", "total"]
]
Key concepts:
mapapplies a function to each element of a listfilterkeeps only elements that match a conditionreducecombines all elements into a single value
Conditional Logic¶
Use if for decisions:
[
"do",
["def", "temperature", 75],
["def", "weather",
["if", [">", "temperature", 80],
"hot",
["if", [">", "temperature", 60],
"warm",
"cool"]]],
["print", "It's", "weather", "today at", "temperature", "degrees"]
]
Data Structures¶
Work with dictionaries (objects) to structure data:
[
"do",
["def", "person", {
"@name": "@Bob",
"@age": 25,
"@city": "@San Francisco"
}],
["def", "name", ["get", "person", "@name"]],
["def", "age", ["get", "person", "@age"]],
// Create a new person with updated age
["def", "older-person", ["set", "person", "@age", ["+", "age", 1]]],
["host", "@print", "@Original person:", "person"],
["host", "@print", "@Person next year:", "older-person"]
]
Modern Data Operations¶
JSL provides powerful special forms for working with collections:
Filtering with where¶
Instead of verbose lambda expressions, use the declarative where form. The fields from each item are automatically available as variables!
JSON Syntax¶
Lisp-Style Syntax¶
Complete example in Lisp-style:
(do
(def users [@
{"name": "Alice", "age": 30, "active": true}
{"name": "Bob", "age": 25, "active": false}
{"name": "Charlie", "age": 35, "active": true}])
; Filter active users - fields are automatically available!
(def active-users (where users active))
; Complex conditions
(def active-adults (where users
(and active (> age 30))))
(host @print "Active adults:" active-adults))
Transforming with transform¶
Reshape data declaratively:
[
"do",
["def", "products", [
{"@name": "@Widget", "@price": 29.99, "@stock": 100}
]],
// Add discount field
["def", "discounted", ["transform", "products",
["assign", "@discount", ["*", "price", 0.1]]]],
// Pick only certain fields
["def", "summary", ["transform", "products",
["pick", "@name", "@price"]]],
["host", "@print", "@Products with discount:", "discounted"]
]
Putting It Together: A Complete Example¶
Let's build a program that processes a list of people:
[
"do",
// Sample data
["def", "people", [
{"name": "Alice", "age": 30, "city": "NYC"},
{"name": "Bob", "age": 25, "city": "SF"},
{"name": "Charlie", "age": 35, "city": "NYC"},
{"name": "Diana", "age": 28, "city": "LA"}
]],
// Helper functions
["def", "get-name", ["lambda", ["person"], ["get", "person", "name"]]],
["def", "get-age", ["lambda", ["person"], ["get", "person", "age"]]],
["def", "is-adult", ["lambda", ["person"], [">=", ["get-age", "person"], 18]]],
["def", "lives-in-nyc", ["lambda", ["person"], ["=", ["get", "person", "city"], "NYC"]]],
// Process the data
["def", "adults", ["filter", "is-adult", "people"]],
["def", "nyc-adults", ["filter", "lives-in-nyc", "adults"]],
["def", "nyc-names", ["map", "get-name", "nyc-adults"]],
["def", "average-age",
["/", ["reduce", "+", ["map", "get-age", "adults"], 0], ["length", "adults"]]],
// Output results
["print", "All people:", ["map", "get-name", "people"]],
["print", "Adults in NYC:", "nyc-names"],
["print", "Average age of adults:", "average-age"]
]
This program demonstrates:
- Working with structured data (lists and dictionaries)
- Creating helper functions for common operations
- Chaining operations together (filter, then map)
- Computing aggregates (average age)
What You've Learned¶
Congratulations! You now understand:
- Prefix notation - operators come first
- Variables - using
defto bind values to names - Functions - creating them with
lambda - Lists and dictionaries - fundamental data structures
- Higher-order functions -
map,filter,reduce - Conditional logic - making decisions with
if - JSON structure - how code and data are the same
Next Steps¶
Ready to learn more? Try these tutorials:
- Working with Functions - Advanced function concepts
- Data Manipulation - Complex data processing patterns
- Code Serialization - Sending code over networks
- Distributed Computing - Building distributed applications
Practice Exercises¶
Try building these programs yourself:
-
FizzBuzz: Print numbers 1-100, but "Fizz" for multiples of 3, "Buzz" for multiples of 5, and "FizzBuzz" for multiples of both.
-
Word Counter: Given a list of words, count how many times each word appears.
-
Temperature Converter: Create functions to convert between Celsius and Fahrenheit.
-
Shopping Cart: Calculate the total price of items in a shopping cart, including tax.
Ready to tackle these? You have all the tools you need!