2019-12-12 01:25:32 +03:00
## Blocks and scoping
### Names introduced by a block shadow names introduced in outer scopes
For example:
2024-07-10 17:46:18 +03:00
``` unison
2019-12-12 01:25:32 +03:00
ex thing =
thing y = y
-- refers to `thing` in this block
-- not the argument to `ex`
bar x = thing x + 1
bar 42
> ex "hello"
```
2024-07-10 19:17:15 +03:00
``` ucm
2019-12-12 01:25:32 +03:00
2023-12-22 14:55:24 +03:00
Loading changes detected in scratch.u.
2019-12-12 01:25:32 +03:00
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update` , here's how your codebase would
change:
⍟ These new definitions are ok to `add` :
ex : thing -> Nat
2020-04-08 21:25:19 +03:00
2019-12-12 01:25:32 +03:00
Now evaluating any watch expressions (lines starting with
`>` )... Ctrl+C cancels.
8 | > ex "hello"
⧩
43
```
### Whether a block shadows outer names doesn't depend on the order of bindings in the block
The `thing` reference in `bar` refers to the one declared locally in the block that `bar` is part of. This is true even if the declaration which shadows the outer name appears later in the block, for instance:
2024-07-10 17:46:18 +03:00
``` unison
2019-12-12 01:25:32 +03:00
ex thing =
bar x = thing x + 1
thing y = y
bar 42
> ex "hello"
```
2024-07-10 19:17:15 +03:00
``` ucm
2019-12-12 01:25:32 +03:00
2023-12-22 14:55:24 +03:00
Loading changes detected in scratch.u.
2019-12-12 01:25:32 +03:00
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update` , here's how your codebase would
change:
⍟ These new definitions are ok to `add` :
ex : thing -> Nat
2020-04-08 21:25:19 +03:00
2019-12-12 01:25:32 +03:00
Now evaluating any watch expressions (lines starting with
`>` )... Ctrl+C cancels.
6 | > ex "hello"
⧩
43
```
### Blocks use lexical scoping and can only reference definitions in parent scopes or in the same block
This is just the normal lexical scoping behavior. For example:
2024-07-10 17:46:18 +03:00
``` unison
2019-12-12 01:25:32 +03:00
ex thing =
bar x = thing x + 1 -- references outer `thing`
baz z =
thing y = y -- shadows the outer `thing`
thing z -- references the inner `thing`
bar 42
> ex (x -> x * 100)
```
2024-07-10 19:17:15 +03:00
``` ucm
2019-12-12 01:25:32 +03:00
2023-12-22 14:55:24 +03:00
Loading changes detected in scratch.u.
2019-12-12 01:25:32 +03:00
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update` , here's how your codebase would
change:
⍟ These new definitions are ok to `add` :
2020-10-22 05:47:25 +03:00
ex : (Nat ->{g} Nat) ->{g} Nat
2020-04-08 21:25:19 +03:00
2019-12-12 01:25:32 +03:00
Now evaluating any watch expressions (lines starting with
`>` )... Ctrl+C cancels.
8 | > ex (x -> x * 100)
⧩
4201
```
2024-07-10 17:46:18 +03:00
Here's another example, showing that bindings cannot reference bindings declared in blocks nested in the *body* (the final expression) of a block:
2019-12-12 01:25:32 +03:00
2024-07-10 17:46:18 +03:00
``` unison
2019-12-12 01:25:32 +03:00
ex thing =
bar x = thing x + 1 -- refers to outer thing
let
thing y = y
bar 42
> ex (x -> x * 100)
```
2024-07-10 19:17:15 +03:00
``` ucm
2019-12-12 01:25:32 +03:00
2023-12-22 14:55:24 +03:00
Loading changes detected in scratch.u.
2019-12-12 01:25:32 +03:00
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update` , here's how your codebase would
change:
⍟ These new definitions are ok to `add` :
2020-10-22 05:47:25 +03:00
ex : (Nat ->{g} Nat) ->{g} Nat
2020-04-08 21:25:19 +03:00
2019-12-12 01:25:32 +03:00
Now evaluating any watch expressions (lines starting with
`>` )... Ctrl+C cancels.
7 | > ex (x -> x * 100)
⧩
4201
```
### Blocks can define one or more functions which are recursive or mutually recursive
2024-07-10 17:46:18 +03:00
We call these groups of definitions that reference each other in a block *cycles* . For instance:
2019-12-12 01:25:32 +03:00
2024-07-10 17:46:18 +03:00
``` unison
2019-12-12 01:25:32 +03:00
sumTo n =
-- A recursive function, defined inside a block
go acc n =
if n == 0 then acc
2021-12-16 01:38:51 +03:00
else go (acc + n) (drop n 1)
2019-12-12 01:25:32 +03:00
go 0 n
ex n =
-- Two mutually recursive functions, defined in a block
ping x = pong (x + 1)
pong x = ping (x + 2)
ping 42
```
2024-07-10 19:17:15 +03:00
``` ucm
2019-12-12 01:25:32 +03:00
2023-12-22 14:55:24 +03:00
Loading changes detected in scratch.u.
2019-12-12 01:25:32 +03:00
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update` , here's how your codebase would
change:
⍟ These new definitions are ok to `add` :
2020-10-22 05:47:25 +03:00
ex : n -> r
2019-12-12 01:25:32 +03:00
sumTo : Nat -> Nat
```
The `go` function is a one-element cycle (it reference itself), and `ping` and `pong` form a two-element cycle.
### Cyclic references or forward reference must be guarded
For instance, this works:
2024-07-10 17:46:18 +03:00
``` unison
2019-12-12 01:25:32 +03:00
ex n =
ping x = pong + 1 + x
pong = 42
ping 0
```
2024-07-10 19:17:15 +03:00
``` ucm
2019-12-12 01:25:32 +03:00
2023-12-22 14:55:24 +03:00
Loading changes detected in scratch.u.
2019-12-12 01:25:32 +03:00
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update` , here's how your codebase would
change:
⍟ These new definitions are ok to `add` :
ex : n -> Nat
```
Since the forward reference to `pong` appears inside `ping` .
This, however, will not compile:
2024-07-10 17:46:18 +03:00
``` unison
2019-12-12 01:25:32 +03:00
ex n =
pong = ping + 1
ping = 42
pong
```
2024-07-10 19:17:15 +03:00
``` ucm
2019-12-12 01:25:32 +03:00
2023-12-22 14:55:24 +03:00
Loading changes detected in scratch.u.
2024-01-25 19:50:27 +03:00
These definitions depend on each other cyclically but aren't guarded by a lambda: pong8
2019-12-12 01:25:32 +03:00
2 | pong = ping + 1
3 | ping = 42
```
This also won't compile; it's a cyclic reference that isn't guarded:
2024-07-10 17:46:18 +03:00
``` unison
2019-12-12 01:25:32 +03:00
ex n =
loop = loop
loop
```
2024-07-10 19:17:15 +03:00
``` ucm
2019-12-12 01:25:32 +03:00
2023-12-22 14:55:24 +03:00
Loading changes detected in scratch.u.
2024-01-25 19:50:27 +03:00
These definitions depend on each other cyclically but aren't guarded by a lambda: loop8
2019-12-12 01:25:32 +03:00
2 | loop = loop
```
This, however, will compile. This also shows that `'expr` is another way of guarding a definition.
2024-07-10 17:46:18 +03:00
``` unison
2019-12-12 01:25:32 +03:00
ex n =
loop = '(!loop)
!loop
```
2024-07-10 19:17:15 +03:00
``` ucm
2019-12-12 01:25:32 +03:00
2023-12-22 14:55:24 +03:00
Loading changes detected in scratch.u.
2019-12-12 01:25:32 +03:00
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update` , here's how your codebase would
change:
⍟ These new definitions are ok to `add` :
2020-10-22 05:47:25 +03:00
ex : n -> r
2019-12-12 01:25:32 +03:00
```
2024-07-10 17:46:18 +03:00
Just don't try to run it as it's an infinite loop\!
2019-12-12 01:25:32 +03:00
### Cyclic definitions in a block don't have access to any abilities
The reason is it's unclear what the order should be of any requests that are made. It can also be viewed of a special case of the restriction that elements of a cycle must all be guarded. Here's an example:
2024-07-10 17:46:18 +03:00
``` unison
2021-08-24 21:33:27 +03:00
structural ability SpaceAttack where
2019-12-12 01:25:32 +03:00
launchMissiles : Text -> Nat
ex n =
zap1 = launchMissiles "neptune" + zap2
zap2 = launchMissiles "pluto" + zap1
zap1
```
2024-07-10 19:17:15 +03:00
``` ucm
2019-12-12 01:25:32 +03:00
2023-12-22 14:55:24 +03:00
Loading changes detected in scratch.u.
2020-10-21 01:26:46 +03:00
The expression in red needs the {SpaceAttack} ability, but this location does not have access to any abilities.
2019-12-12 01:25:32 +03:00
5 | zap1 = launchMissiles "neptune" + zap2
```
2024-07-10 17:46:18 +03:00
### The *body* of recursive functions can certainly access abilities
2019-12-12 01:25:32 +03:00
For instance, this works fine:
2024-07-10 17:46:18 +03:00
``` unison
2021-08-24 21:33:27 +03:00
structural ability SpaceAttack where
2019-12-12 01:25:32 +03:00
launchMissiles : Text -> Nat
ex n =
zap1 planet = launchMissiles planet + zap2 planet
zap2 planet = launchMissiles planet + zap1 planet
zap1 "pluto"
```
2024-07-10 19:17:15 +03:00
``` ucm
2019-12-12 01:25:32 +03:00
2023-12-22 14:55:24 +03:00
Loading changes detected in scratch.u.
2019-12-12 01:25:32 +03:00
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update` , here's how your codebase would
change:
⍟ These new definitions are ok to `add` :
2021-08-24 21:33:27 +03:00
structural ability SpaceAttack
2019-12-12 01:25:32 +03:00
ex : n ->{SpaceAttack} Nat
```
### Unrelated definitions not part of a cycle and are moved after the cycle
For instance, `zap` here isn't considered part of the cycle (it doesn't reference `ping` or `pong` ), so this typechecks fine:
2024-07-10 17:46:18 +03:00
``` unison
2021-08-24 21:33:27 +03:00
structural ability SpaceAttack where
2019-12-12 01:25:32 +03:00
launchMissiles : Text -> Nat
ex n =
ping x = pong (x + 1)
zap = launchMissiles "neptune"
pong x = ping (x + 2)
ping 42
```
2024-07-10 19:17:15 +03:00
``` ucm
2019-12-12 01:25:32 +03:00
2023-12-22 14:55:24 +03:00
Loading changes detected in scratch.u.
2019-12-12 01:25:32 +03:00
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update` , here's how your codebase would
change:
⍟ These new definitions are ok to `add` :
2021-08-24 21:33:27 +03:00
structural ability SpaceAttack
2020-10-22 05:47:25 +03:00
ex : n ->{SpaceAttack} r
2019-12-12 01:25:32 +03:00
```
This is actually parsed as if you moved `zap` after the cycle it find itself a part of:
2024-07-10 17:46:18 +03:00
``` unison
2021-08-24 21:33:27 +03:00
structural ability SpaceAttack where
2019-12-12 01:25:32 +03:00
launchMissiles : Text -> Nat
ex n =
ping x = pong (x + 1)
pong x = ping (x + 2)
zap = launchMissiles "neptune"
ping 42
```
2024-07-10 19:17:15 +03:00
``` ucm
2019-12-12 01:25:32 +03:00
2023-12-22 14:55:24 +03:00
Loading changes detected in scratch.u.
2019-12-12 01:25:32 +03:00
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update` , here's how your codebase would
change:
⍟ These new definitions are ok to `add` :
2021-08-24 21:33:27 +03:00
structural ability SpaceAttack
2020-10-22 05:47:25 +03:00
ex : n ->{SpaceAttack} r
2019-12-12 01:25:32 +03:00
```