Tutorial
A step-by-step guide to learning the Meow programming language. Each section builds on the previous one and includes runnable examples.
Prerequisites
- Go 1.26+ installed
- Meow compiler installed (see Installation)
Verify your installation:
meow version
1. Hello, World!
Create a file called hello.nyan:
nya("Hello, World!")
Run it:
meow run hello.nyan
Output:
Hello, World!
nya is Meow’s print function. It prints its arguments separated by spaces, followed by a newline.
You can also build a native binary:
meow build hello.nyan -o hello
./hello
2. Variables and Types
Declare variables with nyan:
nyan name = "Nyantyu"
nyan age = 3
nyan weight = 4.2
nyan is_cute = yarn # true
nyan is_grumpy = hairball # false
nyan nothing = catnap # nil
Meow supports optional type annotations:
nyan name string = "Nyantyu"
nyan age int = 3
nyan weight float = 4.2
nyan is_cute bool = yarn
Type annotations help catch errors at compile time and generate faster code. Available types: int, float, string, bool, furball, litter.
Print multiple values:
nyan name = "Nyantyu"
nyan age = 3
nya(name, "is", age, "years old")
# => Nyantyu is 3 years old
3. Functions
Define functions with meow and return values with bring:
meow greet(name string) string {
bring "Hello, " + name + "!"
}
nya(greet("Nyantyu")) # => Hello, Nyantyu!
nya(greet("Tyako")) # => Hello, Tyako!
Functions can have typed parameters and return types:
meow add(a int, b int) int {
bring a + b
}
nya(add(3, 7)) # => 10
Go-style grouped types — parameters without a type annotation inherit from the next one:
meow multiply(a, b int) int {
bring a * b
}
Functions that don’t bring a value return catnap (nil) implicitly.
4. Control Flow
Conditionals
Use sniff for if, scratch for else:
meow check_age(age int) string {
sniff (age < 1) {
bring "kitten"
} scratch sniff (age < 7) {
bring "adult"
} scratch {
bring "senior"
}
}
nya(check_age(0)) # => kitten
nya(check_age(3)) # => adult
nya(check_age(10)) # => senior
Loops
Count form — iterates from 0 to n-1:
purr i (5) {
nya(i)
}
# Output: 0, 1, 2, 3, 4
Range form — iterates from a to b inclusive:
purr i (1..5) {
nya(i)
}
# Output: 1, 2, 3, 4, 5
FizzBuzz example:
meow fizzbuzz(n int) string {
sniff (n % 15 == 0) {
bring "FizzBuzz"
} scratch sniff (n % 3 == 0) {
bring "Fizz"
} scratch sniff (n % 5 == 0) {
bring "Buzz"
} scratch {
bring to_string(n)
}
}
purr i (1..20) {
nya(fizzbuzz(i))
}
5. Lists and Functional Operations
Create lists with square brackets:
nyan nums = [1, 2, 3, 4, 5]
nya(nums) # => [1, 2, 3, 4, 5]
nya(len(nums)) # => 5
nya(nums[0]) # => 1
nya(head(nums)) # => 1
nya(tail(nums)) # => [2, 3, 4, 5]
Map with lick
Apply a function to every element:
nyan nums = [1, 2, 3, 4, 5]
nyan doubled = lick(nums, paw(x) { x * 2 })
nya(doubled) # => [2, 4, 6, 8, 10]
Filter with picky
Keep elements matching a predicate:
nyan nums = [1, 2, 3, 4, 5]
nyan evens = picky(nums, paw(x) { x % 2 == 0 })
nya(evens) # => [2, 4]
Reduce with curl
Fold a list into a single value:
nyan nums = [1, 2, 3, 4, 5]
nyan sum = curl(nums, 0, paw(acc, x) { acc + x })
nya(sum) # => 15
Building lists
nyan cats = ["Nyantyu", "Tyako", "Tyomusuke"]
nyan more_cats = append(cats, "Tama")
nya(more_cats) # => [Nyantyu, Tyako, Tyomusuke, Tama]
6. Lambdas and Pipes
Lambdas
Anonymous functions are created with paw:
nyan double = paw(x int) { x * 2 }
nya(double(5)) # => 10
nyan greet = paw(name string) { "Hello, " + name }
nya(greet("Nyantyu")) # => Hello, Nyantyu
Lambdas have a single expression as their body.
Pipe Operator
The |=| operator chains operations by passing the left value as the first argument to the right:
nyan nums = [1, 2, 3, 4, 5]
# Without pipe
nya(lick(nums, paw(x) { x * 2 }))
# With pipe — same result, more readable
nums |=| lick(paw(x) { x * 2 }) |=| nya
Chain multiple operations:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|=| picky(paw(x) { x % 2 == 0 })
|=| lick(paw(x) { x * x })
|=| nya
# => [4, 16, 36, 64, 100]
7. Pattern Matching
Use peek to match a value against patterns:
meow describe(n int) string {
bring peek(n) {
0 => "zero",
1..10 => "low",
11..100 => "medium",
_ => "high"
}
}
nya(describe(0)) # => zero
nya(describe(5)) # => low
nya(describe(50)) # => medium
nya(describe(999)) # => high
Patterns:
- Literal:
0,"hello",yarn - Range:
1..10(inclusive) - Wildcard:
_(matches anything)
Always include a wildcard _ as the last arm to ensure all cases are covered.
8. Error Handling
Raising Errors
Use hiss to raise an error:
meow divide(a int, b int) int {
sniff (b == 0) {
hiss("division by zero")
}
bring a / b
}
Catching with gag
nyan result = gag(paw() { divide(10, 0) })
sniff (is_furball(result)) {
nya("Error caught:", result)
} scratch {
nya("Result:", result)
}
# => Error caught: Hiss! division by zero
Recovery with ~>
The ~> operator provides concise error recovery:
# Use a fallback value
nyan val = divide(10, 0) ~> 0
nya(val) # => 0
# Use a handler function
nyan val2 = divide(10, 0) ~> paw(err) {
nya("Handling error:", err)
42
}
nya(val2) # => 42
9. Structs (Kitty)
Define composite types with kitty:
kitty Cat {
name: string
age: int
}
nyan nyantyu = Cat("Nyantyu", 3)
nyan tyako = Cat("Tyako", 5)
nya(nyantyu) # => Cat{name: Nyantyu, age: 3}
nya(nyantyu.name) # => Nyantyu
nya(nyantyu.age) # => 3
Use kitty types in functions:
meow introduce(cat) {
nya(cat.name + " is " + to_string(cat.age) + " years old")
}
introduce(nyantyu) # => Nyantyu is 3 years old
introduce(tyako) # => Tyako is 5 years old
10. Standard Library
File I/O
nab "file"
# Read entire file
nyan content = file.snoop("data.txt")
nya(content)
# Read file line by line
nyan lines = file.stalk("data.txt")
lines |=| lick(paw(line) { "=> " + line }) |=| nya
HTTP Client
nab "http"
# GET request
http.pounce("https://httpbin.org/get") |=| nya
# POST with JSON body
http.toss("https://httpbin.org/post", {
"name": "Nyantyu",
"age": 3
}) |=| nya
# PUT
http.knead("https://httpbin.org/put", {"name": "Tyako"}) |=| nya
# DELETE
http.swat("https://httpbin.org/delete") |=| nya
With custom headers:
nab "http"
nyan response = http.pounce("https://api.example.com/data", {
"headers": {
"Authorization": "Bearer my_token"
}
})
nya(response)
See Standard Library for the full API reference.
11. Testing
Create a test file with the _test.nyan suffix:
# math_test.nyan
nab "testing"
meow test_addition() {
expect(1 + 1, 2, "basic addition")
expect(10 + 20, 30, "larger addition")
}
meow test_division() {
expect(10 / 2, 5, "basic division")
nyan result = gag(paw() { 10 / 0 })
judge(is_furball(result), "division by zero should error")
}
Run tests:
meow test math_test.nyan
Output:
PASS: test_addition
PASS: test_division
All 2 tests passed, nya~!
Output Verification Tests
Use the catwalk_ prefix with # Output: blocks:
meow catwalk_hello() {
nya("Hello, World!")
}
# Output:
# Hello, World!
Assertions
judge(condition)— assert truthyexpect(actual, expected)— assert equalrefuse(condition)— assert falsy
See Standard Library for details.
12. Build and Tools
CLI Commands
meow run file.nyan # Run a .nyan file
meow build file.nyan [-o name] # Build a native binary
meow transpile file.nyan # Show generated Go code
meow test [files...] # Run test files
meow fmt [files...] # Format .nyan files
meow lint [files...] # Check for style issues
meow version # Show version info
meow help [command] # Show help
Viewing Generated Go Code
Use transpile to see what Go code Meow generates:
meow transpile hello.nyan
This is useful for understanding how Meow features map to Go.
Next Steps
- Language Reference — Complete keyword and operator reference
- Language Specification — Formal grammar and semantics
- Standard Library — Full API documentation
- Effective Meow — Idiomatic patterns and best practices
- Cookbook — Task-based recipes
- Meow vs Go — For Go developers learning Meow