Skip to content
Snippets Groups Projects
Commit d406c383 authored by nanocryk's avatar nanocryk
Browse files

Option type instead of panics, optimisation suggestions, better annonymous...

Option type instead of panics, optimisation suggestions, better annonymous functions support, first part of standard library
parent b60069c9
No related branches found
No related tags found
1 merge request!6WIP: RFC 5 : New Scalable Blockchain Protocol
...@@ -374,7 +374,8 @@ by using anonymous functions. ...@@ -374,7 +374,8 @@ by using anonymous functions.
f2 = map [0, 1, 2] ((|item a| + item 1) 1) f2 = map [0, 1, 2] ((|item a| + item 1) 1)
``` ```
At compilation anonymous functions are converted back to normal functions. There can be only one depth of anonymous function in the compiled script. If there are more, the
compiler will translate some into line functions to respect this limitation.
#### Ranges #### Ranges
...@@ -414,10 +415,9 @@ The value function `5` takes no parameter and represents the value `5`. Its sign ...@@ -414,10 +415,9 @@ The value function `5` takes no parameter and represents the value `5`. Its sign
``` ```
`V` means it's a value and is not composed of simpler functions. To make signatures clearer, we'll `V` means it's a value and is not composed of simpler functions. To make signatures clearer, we'll
provide the meaning of values with types such as `Int`, `Bool`, `Key`, etc. However these subtypes provide the meaning of values with types starting in upper case such as `Int`, `Bool`, `Key`, etc.
will not be checked at runtime as the meaning of a value will be assumed by the function. Thus, it However these subtypes will not be checked at runtime as the meaning of a value will be assumed by
will be possible to arithmetically add *keys* as if they were *integers*, or to perform a boolean the function, and should be checked by the compiler.
AND.
The function `add` takes 3 values (type and 2 values to add) and return a new value. The function `add` takes 3 values (type and 2 values to add) and return a new value.
...@@ -442,34 +442,30 @@ and returning the result. ...@@ -442,34 +442,30 @@ and returning the result.
add :: DataType -> Int -> (Int -> Int) add :: DataType -> Int -> (Int -> Int)
``` ```
The signature of an array is : A function like `map` take an array and a function as parameters. Its signature is :
```txt ```txt
[0 1 2] :: Int -> Int! map :: [a] -> (a -> b) -> [b]
``` ```
`!` means the function can panic and return a "false panic". If a function takes an `Int` as Letters `a` and `b` denotes generic parameters. They can be of any type (a value or a function) as
parameter and is called with a panic value, it's not executed and panic itself, propagating the long as all `a` are bound to the same concret type, same goes for `b`.
panic upward. If the panic goes out of the main function, it returns `false`. However, if the
parameter have a `!` mark, the function can be executed as the panic behavier is handled by the
function. The mark `?` can also be used an is a "true panic", and makes the main function returns
`true` if it leaks out of it.
To make it more readable and to express it's an array, we also write it as : The signature of an array is :
```txt ```txt
[0 1 2] :: [Int] [0 1 2] :: Int -> Int?
``` ```
A function like `map` take an array and a function as parameters. Its signature is : `a?` means the function may return **some** `a` or **none** (in case the index is out of bound).
Value can be *unwrapped* with the `unwrap :: value:a? -> some:(a -> b) -> none:b -> b` function.
To make it more readable and to express it's an array, we also write it as :
```txt ```txt
map :: [a] -> (a -> b) -> [b] [0 1 2] :: [Int]
``` ```
Letters `a` and `b` denotes generic parameters. They can be of any type (a value or a function) as
long as all `a` are bound to the same concret type, same goes for `b`.
#### Subscripts #### Subscripts
It's possible to use subscripts to separate code in multiple smaller pieces. It also allows It's possible to use subscripts to separate code in multiple smaller pieces. It also allows
...@@ -508,8 +504,7 @@ main function returns a value (a function taking no parameters). ...@@ -508,8 +504,7 @@ main function returns a value (a function taking no parameters).
A function `a` can only use `b` if `b` is declared before `a`. A function `b` can only be passed A function `a` can only use `b` if `b` is declared before `a`. A function `b` can only be passed
as argument to `a` only if `b` is declared before `a`. This 2 rules prevent any sort of recursion. as argument to `a` only if `b` is declared before `a`. This 2 rules prevent any sort of recursion.
To simplify scripts writing, functions can be written in any order and will be reordered For annonymous functions, they are virtually placed before all functions they use, then these rules are checked.
automatically.
### Compilation ### Compilation
...@@ -531,8 +526,11 @@ Then, each fonction contains on of these opcodes. ...@@ -531,8 +526,11 @@ Then, each fonction contains on of these opcodes.
| `0b1101XXXX` | `grpXXXX+2` | Create a group of the following `XXXX + 2` items. The first item should be a function call, and the following items its parameters. | `0b1101XXXX` | `grpXXXX+2` | Create a group of the following `XXXX + 2` items. The first item should be a function call, and the following items its parameters.
| `0b1110000X` | `datX+1` | Use data with its `size` stored in the next `X + 1` following bytes, and the data in the `size` next bytes. If the size is 0 a null-length value will be created. | `0b1110000X` | `datX+1` | Use data with its `size` stored in the next `X + 1` following bytes, and the data in the `size` next bytes. If the size is 0 a null-length value will be created.
| `0b1110001X` | `arrX+1` | Create an *array function* with a `size` stored in the next `X + 1` following bytes, then `size` opcodes defining each value. If the size is 0 an empty array will be created. | `0b1110001X` | `arrX+1` | Create an *array function* with a `size` stored in the next `X + 1` following bytes, then `size` opcodes defining each value. If the size is 0 an empty array will be created.
| `0b111001..` | | | `0b11100100` | `anf` | Create in place an anonymous function whose body is the next item.
| `0b1111....` | | *Unused opcodes. Their presence makes the script returns `true` to allow new opcodes additions with soft-forks.* | `0b111001.1` | |
| `0b1110011.` | |
| `0b111001..` | | *Unused opcodes. Their presence makes the script returns `true` to allow new opcodes additions with soft-forks.*
| `0b1111XXXX` | `anp` | Use annonymous function parameter `XXXX` (0-15)
| `0b11111111` | `use` | *Can only be used as the only opcode of a function*. Allow to refeer to a subscript by providing its hash stored in the next 32 bytes. When this function is used in the script, the subscript with the provided hash can be provided and its final function is called. If the subscript is not provided, the return value is the opcode following the hash. If this opcode is another `use`, then the subscript is mandatory and its absence prevent the script from running (making it invalid). | `0b11111111` | `use` | *Can only be used as the only opcode of a function*. Allow to refeer to a subscript by providing its hash stored in the next 32 bytes. When this function is used in the script, the subscript with the provided hash can be provided and its final function is called. If the subscript is not provided, the return value is the opcode following the hash. If this opcode is another `use`, then the subscript is mandatory and its absence prevent the script from running (making it invalid).
### System functions list ### System functions list
...@@ -542,12 +540,14 @@ Then, each fonction contains on of these opcodes. ...@@ -542,12 +540,14 @@ Then, each fonction contains on of these opcodes.
| | | **Primitives** | | | **Primitives**
| `00` | `true :: Bool` | Represents a "true" value. | `00` | `true :: Bool` | Represents a "true" value.
| `01` | `false :: Bool` | Represents a "false" value. | `01` | `false :: Bool` | Represents a "false" value.
| `02` | `step :: begin:Int -> step:Int -> end:Int -> [Int]` | Returns an array of numbers from `begin` to `end` (excluded) with a step of `step`. | `??` | `some :: a -> a?` | Wraps some value.
| `??` | `none :: a?` | Wraps no value.
| `??` | `step :: begin:Int -> step:Int -> end:Int -> [Int]` | Returns an array of numbers from `begin` to `end` (excluded) with a step of `step`.
| | | | | |
| | | **Function operations** | | | **Function operations**
| `??` | `if :: condition:Bool -> yes:a -> no:a -> a` | If `condition` is `true`, returns `yes`, `no` otherwise. | `??` | `if :: condition:Bool -> yes:a -> no:a -> a` | If `condition` is `true`, returns `yes`, `no` otherwise.
| `??` | `try :: fun:a!? -> (success:a -> b) -> (failure: Bool -> b) -> result:b` | Try `fun`. If it doesn't panic, calls `success` with returned value, otherwise calls `failure` with the panic boolean type. It returns the value returned by `success` or `failure`. | `??` | `unwrap :: value:a? -> some:(a -> b) -> none:b -> b` | Try to unwrap `value`, calling `some` if there is some value, or `none` if there is not; and return their value.
| `??` | `fold :: array:[a] -> init:b -> fun:(acc:b -> item:a -> b) -> b` | Use `init` as first value of an accumulator, then for each item the accumator is passed to `fun`, and the return value of fun is used as the new value of the accumulator. When the array access panic (out of bound), the final value of the accumulator is returned. | `??` | `fold :: array:[a] -> init:b -> fun:(acc:b -> item:a -> b) -> b` | Use `init` as first value of an accumulator, then for each item the accumator is passed to `fun`, and the return value of fun is used as the new value of the accumulator. When the array returns a *none* value, the final value of the accumulator is returned.
| `??` | `map :: array:[a] -> fun:(item:a -> b) -> [b]` | For each `item` in `array`, calls `fun item`. | `??` | `map :: array:[a] -> fun:(item:a -> b) -> [b]` | For each `item` in `array`, calls `fun item`.
| | | | | |
| | | **Arithmetic operations (generic over a type)** | | | **Arithmetic operations (generic over a type)**
...@@ -555,8 +555,8 @@ Then, each fonction contains on of these opcodes. ...@@ -555,8 +555,8 @@ Then, each fonction contains on of these opcodes.
| `??` | `binarop :: type:OpType -> op:BinaryOp -> x:V -> y:V -> V` | Performs a binary operation on `x` and `y`. `type` specify which algorithm to use (integer operation, interger with power of 10 operation, etc); and `op` specify the binary operation to apply. | `??` | `binarop :: type:OpType -> op:BinaryOp -> x:V -> y:V -> V` | Performs a binary operation on `x` and `y`. `type` specify which algorithm to use (integer operation, interger with power of 10 operation, etc); and `op` specify the binary operation to apply.
| | | | | |
| | | **Arrays operations** | | | **Arrays operations**
| `??` | `value_to_bytes :: V -> [V]` | Convert a value into a array of individual bytes. | `??` | `to_array :: V -> [V]` | Convert a value into a array of individual bytes.
| `??` | `bytes_to_value :: [V] -> V` | Convert a bytes array into an unique value. | `??` | `from_array :: [V] -> V` | Convert a bytes array into an unique value.
| `??` | `split :: array:[a] -> lenghts:[Int] -> [[a]]` | Split an array in multiple parts of `lengths` lengths, the last part containing the remaining items. When spliting out of bounds, empty arrays are returned. | `??` | `split :: array:[a] -> lenghts:[Int] -> [[a]]` | Split an array in multiple parts of `lengths` lengths, the last part containing the remaining items. When spliting out of bounds, empty arrays are returned.
| `??` | `merge :: parts:[[a]] -> [a]` | Merge all parts into one array. | `??` | `merge :: parts:[[a]] -> [a]` | Merge all parts into one array.
| | | | | |
...@@ -689,6 +689,80 @@ grp 3 ...@@ -689,6 +689,80 @@ grp 3
usr5 usr5
``` ```
### Optimisations
- If possible, function lines can be translated to annonymous functions if they make the final
script smaller.
- Annonymous fonctions inside other ones are refractored to follow the "one depth rule" while trying
to optimize the final size.
- Functions may be in any order to simplify writing, and reordered automatically while checking for
circular dependencies.
### Standard library
```txt
# Option
## Apply function if there is some a, other returns none b
bind :: a? -> (a -> b?) -> b?
bind val fun = unwrap val (some fun) none
# Math
sum :: OpType -> [V] -> V
sum type array = fold array 0 (|acc item| binarop type #nadd acc item)
+ :: Int -> Int -> Int
+ a b = binarop #int #nadd a b
- :: Int -> Int -> Int
- a b = binarop #int #nsub a b
* :: Int -> Int -> Int
* a b = binarop #int #nmul a b
== :: V -> V -> Bool
== a b = binarop #int #nadd a b
# Array
len :: [a] -> Int
len array = sum #int (map array (|_| 1))
# Data
## Extract some range from provided data.
## Returned value might be smaller then expected value
data_extract_partial :: V -> Int -> Int -> V
data_extract_partial data begin size = from_array ((split (to_array data) [begin size]) 1)
data_extract :: V -> Int -> Int -> V?
data_extract data begin size =
if (== size len (data_extract_partial data begin size))
(some (data_extract_partial data begin size))
none
# Storage
store_cell_size :: Storage -> Int -> Int?
store_cell_size store index = data_extract store (* index 2) 2
## Cumulative size (do not call directly, can overflow on data if misused)
store_cell_shift :: Storage -> Int -> Int?
store_cell_shift store index = sum (for [0..index] (|i| unwrap (store_cell_size store i) 0))
store_cell :: Storage -> Int -> V?
store_cell store store_size index = ... TODO
# Token
tkn_hash :: Tkn -> V
tkn_hash tkn = data_extract tkn 0 32
tkn_usage :: Tkn -> TknUsage
tkn_usage tkn = data_extract tkn 32 1
tkn_class_store_size :: Tkn -> Int
tkn_class_store_size tkn = data_extract tkn 33 2
tkn_inst_store_size :: Tkn -> Int
tkn_inst_store_size tkn = data_extract tkn 35 2
```
## 6. Applications ## 6. Applications
### Consensus algorithm ### Consensus algorithm
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment