Holiday is over, now I have fun again. No code changes. (0.38.11)
This commit is contained in:
parent
6ee78cc4fb
commit
c44eba681c
2 changed files with 400 additions and 0 deletions
197
docs/arrays.md
Normal file
197
docs/arrays.md
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
# Arrays in Fun
|
||||
|
||||
This guide focuses on arrays: creation, indexing, mutation, iteration, slicing, and common gotchas. It complements the quick overview in types.md with a deeper, example‑driven treatment.
|
||||
|
||||
## What is an array?
|
||||
|
||||
- Ordered, zero‑indexed, mutable sequence of values.
|
||||
- Can hold mixed types (numbers, strings, maps, arrays, …) in the same array.
|
||||
- Bounds‑checked indexing; out‑of‑range access is a runtime error.
|
||||
|
||||
## Creating arrays
|
||||
|
||||
```
|
||||
// literals
|
||||
a = [1, 2, 3]
|
||||
b = ["alpha", "beta"]
|
||||
empty = []
|
||||
|
||||
// nested
|
||||
grid = [[1,2], [3,4]]
|
||||
|
||||
print(typeof(a)) // "array"
|
||||
print(len(a)) // 3
|
||||
```
|
||||
|
||||
Tip: Prefer square‑bracket literals for clarity and performance versus building via repeated push in a hot loop.
|
||||
|
||||
## Indexing (0‑based) and assignment
|
||||
|
||||
```
|
||||
a = [10, 20, 30]
|
||||
print(a[0]) // 10
|
||||
print(a[2]) // 30
|
||||
|
||||
// update in place
|
||||
a[1] = 42
|
||||
print(a) // [10, 42, 30]
|
||||
```
|
||||
|
||||
Notes:
|
||||
- Valid indices are 0..len(a)-1. Using an invalid index raises a runtime error.
|
||||
- Assignment updates the existing array; references pointing to it observe the change.
|
||||
|
||||
## Appending, popping, inserting, removing
|
||||
|
||||
```
|
||||
a = [1]
|
||||
|
||||
// append to end; returns new length
|
||||
push(a, 7) // => 2, a is now [1, 7]
|
||||
|
||||
// pop last element; returns the removed value
|
||||
v = apop(a) // v = 7, a is now [1]
|
||||
|
||||
// insert at index (shifts elements to the right)
|
||||
a = [1, 2, 3]
|
||||
insert(a, 1, 99) // a => [1, 99, 2, 3]
|
||||
|
||||
// remove at index (shifts left)
|
||||
remove(a, 2) // a => [1, 99, 3]
|
||||
```
|
||||
|
||||
## Slicing and concatenation
|
||||
|
||||
```
|
||||
a = [0,1,2,3,4]
|
||||
|
||||
// slice(startInclusive, endExclusive)
|
||||
head = slice(a, 0, 3) // [0,1,2]
|
||||
mid = slice(a, 1, 4) // [1,2,3]
|
||||
|
||||
// concat: join two arrays
|
||||
b = ["x", "y"]
|
||||
ab = concat(a, b) // [0,1,2,3,4,"x","y"]
|
||||
```
|
||||
|
||||
Slicing returns a new array. The original is unchanged.
|
||||
|
||||
## Iteration patterns
|
||||
|
||||
```
|
||||
a = ["a", "b", "c"]
|
||||
|
||||
// index‑based loop
|
||||
for i = 0; i < len(a); i = i + 1 {
|
||||
print(a[i])
|
||||
}
|
||||
|
||||
// enumerate helper (if available in your stdlib setup)
|
||||
#include <utils/iter.fun> as it
|
||||
for pair in it.enumerate(a) {
|
||||
idx = pair[0]
|
||||
val = pair[1]
|
||||
print(to_string(idx) + ":" + val)
|
||||
}
|
||||
```
|
||||
|
||||
## Copying vs. referencing
|
||||
|
||||
Arrays are reference types. Assigning just copies the reference, not the contents:
|
||||
|
||||
```
|
||||
orig = [1, 2]
|
||||
alias = orig // points to the same array
|
||||
alias[0] = 9
|
||||
print(orig) // [9, 2]
|
||||
|
||||
// create a shallow copy via slice
|
||||
copy = slice(orig, 0, len(orig))
|
||||
copy[1] = 7
|
||||
print(orig) // [9, 2]
|
||||
print(copy) // [9, 7]
|
||||
```
|
||||
|
||||
Shallow copies duplicate the top‑level array but not nested structures.
|
||||
|
||||
## Equality
|
||||
|
||||
```
|
||||
print([1,2] == [1,2]) // true
|
||||
print([1,2] == [2,1]) // false
|
||||
```
|
||||
|
||||
Array equality compares length and element‑wise equality recursively.
|
||||
|
||||
## Common utilities
|
||||
|
||||
Depending on your build/stdlib configuration, these helpers may be available:
|
||||
|
||||
- len(a): number of elements
|
||||
- push(a, v), apop(a)
|
||||
- insert(a, idx, v), remove(a, idx)
|
||||
- slice(a, start, end)
|
||||
- concat(a, b)
|
||||
- find(a, v): index or -1
|
||||
- contains(a, v): 1 or 0
|
||||
|
||||
Check your lib directory (e.g., lib/utils) for additional helpers.
|
||||
|
||||
## Error handling and bounds
|
||||
|
||||
```
|
||||
a = [0]
|
||||
// a[1] is out of range → runtime error
|
||||
```
|
||||
|
||||
Tips:
|
||||
- Guard indices: if i < 0 or i >= len(a) { /* handle */ }
|
||||
- Use remove/insert carefully inside loops; indices of following items change.
|
||||
|
||||
## Interop with maps and strings
|
||||
|
||||
```
|
||||
// arrays of maps
|
||||
users = [ {"name":"Ada"}, {"name":"Lin"} ]
|
||||
print(users[1]["name"]) // Lin
|
||||
|
||||
// split/join patterns depend on your stdlib
|
||||
#include <utils/strings.fun> as su // adjust if present in your tree
|
||||
parts = su.split("a,b,c", ",") // ["a","b","c"]
|
||||
csv = su.join(parts, ",") // "a,b,c"
|
||||
```
|
||||
|
||||
## Performance tips
|
||||
|
||||
- Preallocate by building from literals or chunked appends rather than one‑by‑one in very tight loops.
|
||||
- Prefer index loops over repeated remove/insert in the middle of large arrays.
|
||||
- Use slice to copy only when necessary; keep references for read‑only sharing.
|
||||
|
||||
## Examples
|
||||
|
||||
```
|
||||
// filter even numbers
|
||||
src = [0,1,2,3,4,5]
|
||||
dst = []
|
||||
for i = 0; i < len(src); i = i + 1 {
|
||||
v = src[i]
|
||||
if v % 2 == 0 { push(dst, v) }
|
||||
}
|
||||
print(dst) // [0,2,4]
|
||||
|
||||
// flatten one level
|
||||
nested = [[1,2], [3], [], [4,5]]
|
||||
flat = []
|
||||
for i = 0; i < len(nested); i = i + 1 {
|
||||
row = nested[i]
|
||||
for j = 0; j < len(row); j = j + 1 {
|
||||
push(flat, row[j])
|
||||
}
|
||||
}
|
||||
print(flat) // [1,2,3,4,5]
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- types.md — broader overview of core types with quick array examples.
|
||||
- examples/ — many scripts operate on arrays; try play.fun to explore.
|
||||
203
docs/maps.md
Normal file
203
docs/maps.md
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
# Maps in Fun
|
||||
|
||||
This guide focuses on maps: creation, reading/writing by key, checking key presence, iterating keys/values, nesting, and common gotchas. It complements the quick overview in types.md with a deeper, example‑driven treatment.
|
||||
|
||||
## What is a map?
|
||||
|
||||
- Associative container of key → value pairs.
|
||||
- Keys are typically strings; values can be any type (numbers, strings, arrays, maps, …).
|
||||
- Mutable: assigning with m["k"] = v updates the map in place.
|
||||
- Accessing a missing key yields nil (not an error). Use guards or has(m, key).
|
||||
- Maps are not ordered; rely on keys(m) if you need a concrete list of keys.
|
||||
|
||||
## Creating maps
|
||||
|
||||
```
|
||||
// literals
|
||||
user = { "name": "Ada", "age": 37 }
|
||||
empty = {}
|
||||
|
||||
print(typeof(user)) // "map"
|
||||
```
|
||||
|
||||
Nested structures are natural and common:
|
||||
|
||||
```
|
||||
book = {
|
||||
"title": "Fun Handbook",
|
||||
"meta": { "pages": 120, "isbn": "123-456" },
|
||||
"tags": ["lang", "vm"]
|
||||
}
|
||||
print(book["meta"]["pages"]) // 120
|
||||
```
|
||||
|
||||
## Getting and setting by key
|
||||
|
||||
```
|
||||
profile = { "name": "Lin" }
|
||||
|
||||
// read existing key
|
||||
print(profile["name"]) // Lin
|
||||
|
||||
// read missing key → nil
|
||||
print(profile["email"]) // nil
|
||||
|
||||
// write / overwrite
|
||||
profile["email"] = "lin@example.org"
|
||||
profile["name"] = "Linus"
|
||||
print(profile) // {"name":"Linus","email":"lin@example.org"}
|
||||
```
|
||||
|
||||
Notes:
|
||||
- Using a non‑string key is allowed only if your build/runtime supports it; most code uses string keys for portability.
|
||||
- Missing keys produce nil. Compare against nil before converting or indexing:
|
||||
|
||||
```
|
||||
v = profile["phone"]
|
||||
if v == nil { print("no phone on file") }
|
||||
```
|
||||
|
||||
## Checking key existence
|
||||
|
||||
Use has(m, key) to check if a key is present (returns 1 or 0):
|
||||
|
||||
```
|
||||
cfg = { "debug": 1 }
|
||||
print(has(cfg, "debug")) // 1
|
||||
print(has(cfg, "port")) // 0
|
||||
|
||||
if has(cfg, "port") { print(cfg["port"]) } else { print("using default port") }
|
||||
```
|
||||
|
||||
## Iterating maps
|
||||
|
||||
Maps are not inherently ordered. To iterate, first obtain an array of keys or values.
|
||||
|
||||
```
|
||||
user = { "name": "Ada", "age": 38 }
|
||||
|
||||
// iterate known keys (explicit order you choose)
|
||||
order = ["name", "age"]
|
||||
for i = 0; i < len(order); i = i + 1 {
|
||||
k = order[i]
|
||||
print(k + " = " + to_string(user[k]))
|
||||
}
|
||||
|
||||
// discover keys from the map (order may depend on implementation)
|
||||
ks = keys(user) // -> ["name", "age"] (example)
|
||||
for i = 0; i < len(ks); i = i + 1 {
|
||||
k = ks[i]
|
||||
print(k + ": " + to_string(user[k]))
|
||||
}
|
||||
|
||||
// values only
|
||||
vs = values(user) // -> ["Ada", 38]
|
||||
for i = 0; i < len(vs); i = i + 1 { print(to_string(vs[i])) }
|
||||
```
|
||||
|
||||
Tip:
|
||||
- If you need deterministic output, either define the order array explicitly or sort the result of keys(user) using your available utilities before looping.
|
||||
|
||||
## Copying vs. referencing
|
||||
|
||||
Maps are reference types. Assigning copies the reference, not the contents:
|
||||
|
||||
```
|
||||
orig = { "a": 1 }
|
||||
alias = orig
|
||||
alias["a"] = 9
|
||||
print(orig["a"]) // 9
|
||||
|
||||
// To make a shallow copy, rebuild from keys/values
|
||||
src = { "x": 1, "y": 2 }
|
||||
dst = {}
|
||||
ks = keys(src)
|
||||
for i = 0; i < len(ks); i = i + 1 { k = ks[i]; dst[k] = src[k] }
|
||||
|
||||
dst["x"] = 7
|
||||
print(src["x"]) // 1
|
||||
print(dst["x"]) // 7
|
||||
```
|
||||
|
||||
Shallow copies duplicate only the top‑level mapping; nested arrays/maps inside are still shared unless you clone them manually.
|
||||
|
||||
## Equality
|
||||
|
||||
```
|
||||
print({"a":1,"b":2} == {"b":2,"a":1}) // true
|
||||
print({"a":1} == {"a":2}) // false
|
||||
```
|
||||
|
||||
Map equality compares sets of keys and their corresponding values for equality (order does not matter).
|
||||
|
||||
## Common utilities
|
||||
|
||||
Depending on your build/stdlib configuration, these helpers are commonly available:
|
||||
|
||||
- has(m, key): 1 if present, 0 otherwise
|
||||
- keys(m): array of keys
|
||||
- values(m): array of values (parallel to keys(m) order)
|
||||
- len(a) works on arrays; for maps, prefer keys(m) then len(keys(m)) if you need a count
|
||||
|
||||
Check your lib or VM docs (e.g., src/vm/maps) and docs/types.md for availability and details.
|
||||
|
||||
## Interop with arrays and strings
|
||||
|
||||
```
|
||||
// maps inside arrays
|
||||
users = [ {"name":"Ada"}, {"name":"Lin"} ]
|
||||
for i = 0; i < len(users); i = i + 1 {
|
||||
print(users[i]["name"]) // Ada, Lin
|
||||
}
|
||||
|
||||
// arrays inside maps
|
||||
m = { "nums": [1,2,3] }
|
||||
arr = m["nums"]
|
||||
push(arr, 4)
|
||||
print(m["nums"]) // [1,2,3,4]
|
||||
|
||||
// JSON interop is typically via lib/io/json.fun (if enabled in your build)
|
||||
#include <io/json.fun> as json // adjust to your tree and build flags
|
||||
s = json.stringify({"ok":1}) // "{"ok":1}"
|
||||
```
|
||||
|
||||
## Error handling and edge cases
|
||||
|
||||
- Accessing a missing key returns nil. Guard before arithmetic or nested indexing.
|
||||
- Mutating a map while iterating over keys you computed earlier is safe, but remember the keys array won’t update automatically; recompute if needed.
|
||||
- Treat map iteration order as unspecified unless your build guarantees stability. For user‑facing output, specify/derive an order explicitly.
|
||||
|
||||
## Performance tips
|
||||
|
||||
- If you will access many keys, cache ks = keys(m) once and index that array in a loop rather than calling keys(m) repeatedly.
|
||||
- Prefer direct writes (m["k"]=v) over repeatedly rebuilding maps in tight loops.
|
||||
- When copying, copy only required keys instead of cloning the entire map if you only need a subset.
|
||||
|
||||
## Examples
|
||||
|
||||
```
|
||||
// merge defaults into config (without overwriting explicit keys)
|
||||
defaults = { "host":"127.0.0.1", "port":8080, "debug":0 }
|
||||
cfg = { "port": 9000 }
|
||||
|
||||
ks = keys(defaults)
|
||||
for i = 0; i < len(ks); i = i + 1 {
|
||||
k = ks[i]
|
||||
if !has(cfg, k) { cfg[k] = defaults[k] }
|
||||
}
|
||||
print(cfg) // {"port":9000,"host":"127.0.0.1","debug":0}
|
||||
|
||||
// index users by id
|
||||
rows = [ {"id":"u1","name":"Ada"}, {"id":"u2","name":"Lin"} ]
|
||||
by_id = {}
|
||||
for i = 0; i < len(rows); i = i + 1 {
|
||||
r = rows[i]
|
||||
by_id[r["id"]] = r
|
||||
}
|
||||
print(by_id["u2"]["name"]) // Lin
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- types.md — broader overview of core types with quick map examples.
|
||||
- examples/ — there are example scripts involving maps; try play.fun to explore.
|
||||
Loading…
Add table
Add a link
Reference in a new issue