mirror of
https://github.com/Open-Argon/docs.git
synced 2026-10-28 09:43:55 +00:00
155 lines
4.3 KiB
Markdown
155 lines
4.3 KiB
Markdown
# Functions
|
|
|
|
## Declaring a function
|
|
|
|
Functions are declared with `let`, just like variables — a function is a value:
|
|
|
|
```
|
|
let add(a, b) = do
|
|
return a + b
|
|
|
|
term.log(add(2, 3)) # 5
|
|
```
|
|
|
|
For a single-expression body, you can skip `do` and `return` entirely:
|
|
|
|
```
|
|
let square(x) = x * x
|
|
```
|
|
|
|
This is the same pattern used for one-line class methods (see
|
|
[Classes and objects](../classes/README.md)).
|
|
|
|
## Anonymous (lambda) functions
|
|
|
|
Functions don't need a name. An anonymous function is written the same way, just without
|
|
an identifier before the parameter list:
|
|
|
|
```
|
|
term.log(()=10) # a zero-argument anonymous function returning 10
|
|
term.log((x)=10)
|
|
term.log((x,y)=10)
|
|
term.log((x,y,z)=10)
|
|
|
|
# named versions, for comparison:
|
|
term.log(a()=10)
|
|
term.log(b(x)=10)
|
|
```
|
|
|
|
(from [`anonymous_function.ar`](https://git.wbell.dev/Open-Argon/Chloride/src/commit/8e1ee06b88200ab112cf34e49efe969030ea435c/tests/anonymous_function.ar))
|
|
|
|
Anonymous functions are commonly passed directly as arguments, e.g. to `array.map`:
|
|
|
|
```
|
|
term.log(
|
|
array(range(-1000000, 1000000))
|
|
.map((val) = val * val)
|
|
.filter((val) = val < 10000)
|
|
.sort((a, b) = a < b ? -1 : a > b ? 1 : 0)
|
|
)
|
|
```
|
|
|
|
(from [`map_filter_sort.ar`](https://git.wbell.dev/Open-Argon/Chloride/src/commit/8e1ee06b88200ab112cf34e49efe969030ea435c/tests/map_filter_sort.ar) — this also shows
|
|
method chaining on arrays; see [Arrays](../arrays/README.md).)
|
|
|
|
## Default arguments
|
|
|
|
```
|
|
let round(num, precision=1) = do
|
|
...
|
|
```
|
|
|
|
(from [`stdlib/maths/init.ar`](https://git.wbell.dev/Open-Argon/Chloride/src/commit/8e1ee06b88200ab112cf34e49efe969030ea43maths/init.ar))
|
|
|
|
## Variadic arguments: `*args` and `**kwargs`
|
|
|
|
A function can collect any extra positional arguments into an array with `*args`, and any
|
|
extra keyword arguments into a dictionary with `**kwargs`:
|
|
|
|
```
|
|
let f(*args, **kwargs) = do
|
|
term.log(args, kwargs)
|
|
|
|
f("Hello world", *[1, 2, 3], **{x: 1, y: 5, z: 7})
|
|
```
|
|
|
|
(from [`argument_unpacking.ar`](https://git.wbell.dev/Open-Argon/Chloride/src/commit/8e1ee06b88200ab112cf34e49efe969030ea435c/tests/argument_unpacking.ar)) — note that
|
|
`*` and `**` are also used at the **call site** to unpack an existing array/dictionary into
|
|
positional/keyword arguments, exactly like the definition-site collectors.
|
|
|
|
### Mixing required, default, `*args`, and `**kwargs`
|
|
|
|
```
|
|
let f(x, a=null, *args, **kwargs) = do
|
|
return `x=$(x), a=$(a), args=$(args), kwargs=$(kwargs)`
|
|
|
|
term.log(f(1))
|
|
term.log(f(1, 2))
|
|
term.log(f(1, 2, 3))
|
|
term.log(f(a=2, *["this should go to x"]))
|
|
term.log(f(1, a=2, **["this should go to kwargs"]))
|
|
term.log(f(1, a=2, **{wow: "this should go to kwargs"}))
|
|
term.log(f(a=2, **{x: "this should go to x"}))
|
|
```
|
|
|
|
(from
|
|
[`test_mixed_args_defaults_and_unpacking.ar`](https://git.wbell.dev/Open-Argon/Chloride/src/commit/8e1ee06b88200ab112cf34e49efe969030ea435c/tests/test_mixed_args_defaults_and_unpacking.ar))
|
|
|
|
This shows that keyword arguments can fill in named parameters like `x` even when passed
|
|
via `**{x: ...}`, and that unpacking a plain array with `**` still works, filling in
|
|
`kwargs` positionally in the array's order.
|
|
|
|
## Recursion
|
|
|
|
Functions can call themselves normally:
|
|
|
|
```
|
|
let factorial(x) = do
|
|
let n = x - 1
|
|
if (n) return x * factorial(n)
|
|
return 1
|
|
```
|
|
|
|
(from [`factorial.ar`](https://git.wbell.dev/Open-Argon/Chloride/src/commit/8e1ee06b88200ab112cf34e49efe969030ea435c/tests/factorial.ar))
|
|
|
|
## Closures
|
|
|
|
Functions capture variables from their enclosing scope:
|
|
|
|
```
|
|
let f() = do
|
|
let x = 10
|
|
let i = 0
|
|
while (i < 100) do
|
|
i = i + 1
|
|
...
|
|
|
|
let g() = f()
|
|
|
|
g()
|
|
```
|
|
|
|
(from
|
|
[`loop_continue_and_break_test.ar`](https://git.wbell.dev/Open-Argon/Chloride/src/commit/8e1ee06b88200ab112cf34e49efe969030ea435c/tests/loop_continue_and_break_test.ar))
|
|
|
|
## Functions as methods on built-in types
|
|
|
|
You can attach a method directly to a built-in type, e.g. `string`:
|
|
|
|
```
|
|
string.cool(self) = do
|
|
term.log(self, self.length)
|
|
return 10
|
|
|
|
'hello world'.cool()
|
|
string.cool('goodbye world')
|
|
```
|
|
|
|
(from [`class_method.ar`](https://git.wbell.dev/Open-Argon/Chloride/src/commit/8e1ee06b88200ab112cf34e49efe969030ea435c/tests/class_method.ar)) — note the two
|
|
equivalent call styles: as an instance method (`'hello world'.cool()`) or as an explicit
|
|
call on the type passing `self` (`string.cool('goodbye world')`).
|
|
|
|
## Next
|
|
|
|
- [Classes and objects](../classes/README.md)
|
|
- [Error handling](../error-handling/README.md) |