CodeBlocks
A code block is a collection of statements - the basic units of a language(it's a lambda)
[
x = 1
y = 2
x + y
]
The type of such block is [ -> Int]
because the last expression of the block is its result.
From this you could already guess that blocks can be assigned to variable and executed:
x = [1 + 2]
x do echo
So blocks are kinda lazy evaluated code. They can store values from outside:
w = 21
x = [w * 2]
x do echo
This can be used to reduce the coherence of the code.
Put the dependencies necessary for the computation inside block in one place, and send the block to another!
So you can have many producers and one consumer, meaning nothing specific about the producers. // TODO link to example from other chapter
Blocks for code organization
isSHA = [
x = "a/b/c/d"
y = FileSystem readAll: x
y contains: "SHA"
] do
With eval-in-place blocks, you can organize complex calculations without noising your scope with temporary variables.
CodeBlocks with args
add2nums = [a::Int, b::Int -> a + b]
Since blocks always return the last value, ->
here is used to separate the list of arguments and statements. I call it consistency.
Now instead of do
we will send the args itself to it:
result = add2nums a: 21 b: 21
Send blocks as arguments
// btw [ -> ] means no arg no return
Int repeat::[ -> ] = [
repeat do
(this - 1) repeat: repeat
]
5 repeat: [ "UwU" echo ]
If block has args then the types themselves become arguments for a block
Int add2num::[Int, Int -> Int] = [
x = add2num Int: this Int: 31 // types are args
x echo
]
11 add2num: [a, b -> a + b]
What is the answer?
It
If a block of code accepts a single argument, you can omit it and use it
:
Int double::[Int -> Int] = [
x = add2num Int: this
x echo
]
5 double: [it * it]
5 double: [a -> a * a] // same thing
This is very often used in methods for collections:
TODO filter map ...
But do not forget to give unique names if you call one block inside another, niva allows name clashes between different scopes:
{{1 2 3} {4 5 6} {7 8 9}} forEach: [
it forEach: [
// now I cant use the it from the upper scope, it clashed
]
]
{{1 2 3} {4 5 6} {7 8 9}} forEach: [ array ->
it forEach: [ elem ->
elem echo
]
]
Just more examples
Simple
// block with no argument
o = [
// some complicated computations
1 + 41
] do // call block in place, so o == 42
// block with q argument
x = [q::Int -> q + 5]
w = x q: 2 // call block with arguments
w echo
lambda = [str1::String, str2::String -> str1 + " " + str2]
e = lambda str1: "Hello" str2: "World!"
e echo
Int from::[Int, String -> Unit] = [
from Int: 1 String: "sas"
1 echo
]
1 from: [x::Int, y::String -> x echo]
Return block from block
x = [
x = 5 + 5
y = x - 1
z = x + y + 22
z
] do
y = x + 1
y echo
q = [
x = 5 + 5
y = x - 2
z = x + y + 24
[
x + y + z + y
]
] do do
w = q + 1
w echo
LambdaCalculus Prove
This is funny example of hardcore blocks utilization
truly = [t::[ -> ], f::[ -> ] -> t do]
falsy = [t::[ -> ], f::[ -> ] -> f do]
ify = [c::[[ -> ], [ -> ] -> ], t::[ -> ], f::[ -> ] -> c x: t y: f]
ify c: truly t: ["true" echo] f: ["false" echo]
ify c: falsy t: ["true" echo] f: ["false" echo]
Last modified: 14 September 2024