[][src]Module wlambda::prelude

This module defines some default functions and operations available in the WLambda language.

You there are two WLambda modules provided by this module:

WLambda Reference

WLambda is a functional programming language. The main goal of this implementation is the extension of Rust applications with dynamic scripting. The syntax gravitates around the concept that everything is callable like a function. There is special syntax for composing arguments of functions, to give the programmer the ability to express his thoughts as they see fit.

You can use this document as reference or as cover to cover lecture. It starts out with functions and the base data types of WLambda, where I also explain some semantics of the language.

Please note: I expect you to know how to program and be familiar with at least one other dynamic language like JavaScript, Perl or at least Python. The syntax and semantics of WLambda are different from what you might know. Think of it more like a LISP without parenthesis. The syntax is loosely inspired from Smalltalk, LISP and Perl.

Syntax

A more formal introduction to the syntax can be found in the parser API documentation.

Functions (part 1/2)

A function can be defined using the { ... } syntax and the \ _statement_ syntax: To give functions a name, you need to assign them to a variable with the !_name_ = _expr_ syntax.

Closures

Functions take values from the outer scope by copying their value:

!a = 10;
!b = 20;

!add_a_and_b = { a + b }; # function copies the values 10 and 20

!result = add_a_and_b[];

std:assert_eq result 30;

This also means, that functions can not modify the values of the scope they were created in. To do that, you need a referencial data type, that is described further down this document.

Here is an example how we would write the above example by mutating the value in the result variable:

!a = 10;
!b = 20;
!result = $& $none; # Create a weakly captured reference

# function copies the values 10 and 20
# but result is captured by reference. As the weakable reference
# type `$&` is used, it's only weakly captured.
!add_a_and_b = { .result = a + b; };

add_a_and_b[];

std:assert_eq $*result 30; # $* dereferences referencial types

About the weakly capturing of result: It means, that if the outer reference value in result goes out of scope, the reference in the closure does not keep it alive. This is important to prevent cyclic refences where closures keep captured values unneccessarily alive.

You will also need this to make refencial types such as maps ${ } and vectors $[ ] weakly referenced by closures for OOP.

Object Oriented Programming with Closures

This is how you can use a map data type as object which stores methods:

!new_Cat = {!(name) = @;

    # Notice the weakable reference `$&` to prevent
    # reference cylces:

    !self = $& ${
        name = name,
    };

    self.meow = { std:displayln self.name " meows!"; };
    self.get_name = { self.name };

    self
};

!my_cat = new_Cat "Spot";

my_cat.meow[]; # Prints 'Spot meows!'

std:assert_eq my_cat.get_name[] "Spot";

Alternatively you can just make the cat name private:

!new_Cat = {!(name) = @;

    # Notice the weakable reference `$&` to prevent
    # reference cylces:

    !self = ${}; # Just holds the methods

    # Make a strong reference, so the closures DO keep cat_name alive!
    !cat_name = $&& name;

    self.meow = { std:displayln cat_name " meows!"; };

    self.get_name = { $*cat_name };
    self.set_name = { .*cat_name = _; };

    self
};

!my_cat = new_Cat "Spot";

my_cat.meow[]; # Prints 'Spot meows!'

std:assert_eq my_cat.get_name[] "Spot";

my_cat.set_name "Spotty";

std:assert_eq my_cat.get_name[] "Spotty";

Function calling

To call functions, you have at least 3 alternatives. First is the bare _expr_ arg1 arg2 arg3 arg4 syntax. And the second is the delimiter full variant: _expr_[arg1, arg2, arg3, ...]. You can always delimit the first variant using the ( ... ) parenthesis around the whole call. Third you can call a function with a vector as argument with _expr_[[_expr_]], where the second expression should return a vector (if it doesn't it will use the value as first argument).

Here are examples:

# All the second variant:
std:assert_eq[std:str:cat[1, 2, 3], "123"];

# Can also be written as:
std:assert_eq (std:str:cat 1 2 3) "123";

# As the third variant:
!some_args = $[1, 2, 3];
std:assert_eq std:str:cat[[some_args]] "123";

The arguments passed to the function are accessible using the _, _1, _2, ..., _9 variables. If you need to access more arguments the @ variable holds a vector of all arguments.

!twoify = { _ * 2 };

std:assert_eq twoify[2] 4;

!twoify2 = \_ * 2;

std:assert_eq twoify2[2] 4;

# You may also call them directly, notice the parenthesis ( ... ) syntax
# for delimiting the inner function call:
std:assert_eq ({ _ * 2 } 2) 4;

If you want to name arguments, you can use the destructuring assignment syntax:

!add = {!(a, b) = @;
    a + b
};

std:assert_eq add[1, 2] 3;

Function arity checks

Functions check the number of arguments passed to them. The compiler tries to infer the number of arguments the function requires by looking at the parameter variables _ to _9 and @. If the compiler gets it wrong, you can:

  • Define minimum and maximum number of arguments with: {|min < max| ... }
  • Define exact number of arguments with: {|num_of_args| ... }
  • Accept any number of arguments: {|| ... }

For the shortened function syntax there is:

  • \|min < max| ...
  • \|num_of_args| ...
  • \|| ...

Here an example:

!dosomething = {|2 < 4|
    !a = _;
    !b = _1;
    !c = _2;
    !d = _3;

    # Please note: We have to assign _ to _3 here, because
    # the arms of the conditional below have
    # their own set of arguments.

    (is_none c) { a + b } { a * b + c * d }
};

std:assert_eq dosomething[1, 2]         3;
std:assert_eq dosomething[2, 2, 3, 4]  16;

Data Types

None sentinel value: $n or $none

This is a special sentinel value that is returned by functions and when a non existing field of a datastructure is accessed. It's semantic meaning is that there is no value.

Most functions that expect a string value will turn a $none into an empty string. If you need an unambigous representation use std:str:write for dumping WLambda data structures.

Please note for API design: In case of errornous states you should not return a $none but an $error value.

std:assert ~ $n                == $none;
std:assert ~ int[$n]           == 0;
std:assert ~ float[$n]         == 0.0;
std:assert ~ str[$n]           == "";
std:assert ~ std:str:write[$n] == "$n";
std:assert ~ is_none[$n];

Error values: $e expr or $error expr

There are no exceptions in WLambda, except the panic, that halts all execution of the currently running WLambda program. To signal errors, you return an $error value.

These error values, if not handled, will cause a panic of your program. This means, you need to handle returned error values one way or the other.

The error value wraps any value you pass to the $error or $e constructor syntax.

std:assert ~ is_err ~ $e "something went wrong!"

There are more routines except is_err to handle an error. _? will return from the currently executed function up until some given label. on_error executes a function if the second argument was an error value. Otherwise it just passes through the value. unwrap will explicitly cause an panic if an error value was passed to it. All other values will be passed through. And unwrap_err unwraps an error value, it's the opposite of unwrap because it will cause a panic if you don't pass an error value.

Most functions don't accept errors in their arguments. If an error is encountered, a panic will occur. There are only a few functions that accept error values in their arguments:

  • panic
  • _?
  • unwrap_err
  • error_to_str
  • unwrap
  • on_error
  • return
  • break
  • bool
  • type
  • match
  • assert
  • assert_eq
  • is_some
  • is_none
  • is_err
  • is_map
  • is_vec
  • is_fun
  • is_str
  • is_wref
  • is_ref
  • is_bool
  • is_bytes
  • is_sym
  • is_float
  • is_int
  • ==
  • !=
  • std:to_ref
  • std:ref_id
  • std:write_str

All other functions don't accept errors as their argument.

Return on error with _?

!func = { $e "this failed!" };

!other = {
    # some code ...

    _? func[]; # If you would not catch the error value here,
               # the program would panic, as an error value
               # must not be ignored!

    # other code ...

    panic "this will never be reached!";

    # something here...
};

std:assert ~ (unwrap_err other[]) == "this failed!";

_? can take up to 2 arguments. If so, the first argument is interpreted as jump label. That is handy if you want to jump up multiple call frames:

!failing_func = { $e :FAIL };

!func = \:some_unique_label {
    ( _ == 42 ) {
        std:displayln "We got 42!";

        # The `then` branch we are currently in is a call frame.
        # To jump further up the call stack, we need the label
        # we defined for the function above.
        !val = _? :some_unique_label failing_func[];

        std:displayln "Returned:" val;
    }
};

std:assert_eq (unwrap_err ~ func 42) :FAIL;

Handle errors with on_error

!func = {
    (_ == 13) {
        $e "this failed!"
    } {
        "all ok!"
    }
};

!x = $&$n;

# The first function of on_error will be called with the unwrapped
# error if an error occured.
on_error {|4| .x = _; } ~ func 13;
std:assert_eq $*x "this failed!";

!ret = on_error {|4| .x = _; } ~ func 1;
std:assert_eq ret "all ok!";

Booleans

True and false are represented by $t and $f or $true and $false, whatever suits your coding style better.

You can either use a boolean value with two arguments, where $true will call the first argument, and $false the second argument. So to check for truthness you can just do:

!x = 10;
!some_num =
    (x == 10) { "it is ten" } { "it is not ten" };

std:assert_eq some_num "it is ten";

.x = 20;
.some_num =
    (x == 10) { "it is ten" } { "it is not ten" };
std:assert_eq some_num "it is not ten";

You can cast other values into a boolean with the bool function:

std:assert_eq (bool 1)          $true;
std:assert_eq (bool 0)          $false;
std:assert_eq (bool $e :x)      $false;
std:assert_eq (bool $n)         $false;
std:assert_eq (bool "")         $false;
std:assert_eq (bool "0")        $false;
std:assert_eq (bool "1")        $true;
std:assert_eq (bool :0)         $false;
std:assert_eq (bool :1)         $true;
std:assert_eq (bool 0.0)        $false;
std:assert_eq (bool 0.1)        $false;
std:assert_eq (bool 1.0)        $true;
std:assert_eq (bool {})         $true;
std:assert_eq (bool $b"")       $false;
std:assert_eq (bool $b"\x00")   $false;
std:assert_eq (bool $b"\x01")   $true;

You can also check if something is a boolean with is_bool:

std:assert ~ is_bool $true;
std:assert ~ is_bool $false;
std:assert ~ not[is_bool $n];
std:assert ~ not[is_bool ""];
std:assert ~ not[is_bool 0];

64-Bit Integers

64-Bit Floats

Strings

Bytes (or Byte Vectors)

Bytes are a special kind of strings. Their literal form is:

$b"abc";
$b"\xFF\xFD\x00";
$Q/ABCDEF\xFD/;      # \xFD is not an excape sequence here!

Call Properties oy Bytes

You can index inside a byte array by calling it with an integer:

std:assert_eq ($b"ABC" 1) $b"B";

You can extract a whole range when calling with 2 integers:

std:assert_eq ($b"ABCDEF" 2 3) $b"CDE";

If you call a bytes value with a map as argument, the bytes value is converted to a string internally using str and the value from the map is returned:

!some_map = ${ a = 20, b = 30 };

std:assert_eq ($b"a" some_map) 20;
std:assert_eq ($b"b" some_map) 30;

std:assert_eq some_map.$b"a" 20;   # with method call syntax

Byte Conversion Functions

You can convert bytes to strings in a multitude of ways:

  • str bytes
    std:assert_eq (str $b"abc")        "abc";
    std:assert_eq (str $b"abc\xFF")    "abcÿ";
    std:assert_eq (str $Q/ABCDEF\xFD/) "ABCDEF\\xFD";
    
  • std:bytes:to_hex bytes [group-len [group-sep]]
    std:assert_eq (std:bytes:to_hex $b"\xFF\x0A\xBE\xEF")
                  "FF0ABEEF";
    std:assert_eq (std:bytes:to_hex $b"\xFF\x0A\xBE\xEF" 2)
                  "FF 0A BE EF";
    std:assert_eq (std:bytes:to_hex $b"\xFF\x0A\xBE\xEF" 2 ":")
                  "FF:0A:BE:EF";
    
  • std:str:from_utf8 bytes
    std:assert_eq (std:str:from_utf8 $b"\xC3\xA4\xC3\x9F\xC3\xBF") "äßÿ";
    std:assert_eq (std:str:from_utf8 [std:str:to_bytes "äßÿ"])         "äßÿ";
    # broken UTF8 will result in an error:
    std:assert ~ is_err (std:str:from_utf8 $b"\xC3\xC3\xA4\xC3\x9F\xC3\xBF");
    
  • std:str:from_utf8_lossy bytes
    std:assert_eq (std:str:from_utf8_lossy $b"\xC3\xC3\xA4\xC3\x9F\xC3\xBF") "�äßÿ";
    

You can even convert bytes to vectors of integers back and forth:

!v = std:bytes:to_vec $b"ABC";
std:assert_eq (str v) (str $[65, 66, 67]);

std:push v 64;
!b = std:bytes:from_vec v;
std:assert_eq b $b"ABC@";

There is also an invese operation to bytes:to_hex:

std:assert_eq (std:bytes:from_hex ~ std:bytes:to_hex $b"ABC") $b"ABC";

Symbols

Vectors (or Lists)

The literal syntax for vectors (or sometimes also called lists in WLambda) is $[...]. You may write any kind of expression in it and you will get a vector from it.

To access the elements of a vector you have to call a number with a vector as first argument. The field syntax is a more convenient shorthand syntax. The following example demonstrates it:

!add20 = { _ + 20 };

!some_vec = $[1, 2 * 10, add20 10]; 

# Index calling:
std:assert_eq (0 some_vec) 1;
std:assert_eq (1 some_vec) 20;
std:assert_eq (2 some_vec) 30;

# Field syntax:
std:assert_eq some_vec.0 1;
std:assert_eq some_vec.1 20;
std:assert_eq some_vec.2 30;

Splicing

You can splice vectors directly into their literal form with the $[..., * vec_expr, ...] syntax. Here is an example:

!make_some = { $[_ + 1, _ + 2] };

!some_vec = $[ 0, *make_some 1 ];

std:assert_eq some_vec.1 2;
std:assert_eq some_vec.2 3;

# There can be any expression after the `.` if you wrap it into `(...)`:
std:assert_eq some_vec.(1 + 1) 3;

# A more direct example:
std:assert_eq (str $[1,2,*$[3,4]]) "$[1,2,3,4]";

Associative Maps (or String to Value mappings)

Aside from vectors there are associative maps in WLambda. Their syntax is ${ key = expr, ... }. The keys of these maps have to be strings, the values in the literals can be any expression.

You can call a symbol or a string with an associative map to get the value in the map with the string value as key. There is also, like vectors, the field calling syntax. Here are some examples:

!some_map = ${ a = 1, b = 2 };

# Symbol calling:
std:assert_eq (:a some_map) 1;
std:assert_eq (:b some_map) 2;
std:assert_eq ("a" some_map) 1;
std:assert_eq ("b" some_map) 2;

# Field syntax:
std:assert_eq some_map.a 1;
std:assert_eq some_map.b 2;

# There can be any expression after the `.` if you wrap it into `(...)`,
# also strings:
std:assert_eq some_map.("a") 1;
std:assert_eq some_map.("b") 2;

Keys can also be computed at runtime in the literal form:

!some_map = ${ (std:str:cat "a" "b") = 10 };

std:assert_eq (str some_map) "${ab=10}";

Splicing

Like vectors you can splice map values directly into map literals:

!map_gen = { ${ (std:str:cat "_" _) = _ } };

!some_map = ${ a = 10, *map_gen "x" };

std:assert_eq some_map.a 10;
std:assert_eq some_map._x "x";

std:assert_eq (str ${*${a=10}}) "${a=10}";

# As a reminder, a full expression can come after the '*':

std:assert_eq (str ${*map_gen "y"}) $q/${_y="y"}/;

References

Some data structures already have reference characteristics, such as strings, vectors and maps. There are 3 types of references in WLambda that handle different usecases. These referencial types are neccessary to mutate lexical variables from a parent scope. To give an example:

!x = 10;
{ .x = 20; }[];
std:assert_eq x 10; # Yes, this is still 10!

To explain what is going on: Closures take captured values by copy. See also the section about closures at the start of this document. To mutate the outer you need a reference. There are two types of references:

  • $& - A weakable reference, that is captured weakly by closures.
  • $&& - A strong reference, that is captured stongly by closures.

The weakable reference is captured weakly by closures and not keep the referenced value alive if the value reference count drops to zero. The strong references are staying strong and need explicit care to handle:

!x = $& 10;

{ .x = 20; }[]; # Closures implicitly handle weak references

std:assert_eq $*x 20;

And the same with strong references:

!x = $&& 10;

# Explicit handling via reference assignment `.*<var> = <expr>`
{ .*x = 20; }[];

std:assert_eq $*x 20;

Strong references can also be created using the std:to_ref function:

!x = std:to_ref 10;
std:assert_eq (std:write_str x) "$&&10";

Weaken References

You can weaken any of those two types of references manually using the std:weaken function.

!drop_check = $& $f;

# Make a reference to the value 10 and set `drop_check` to $true
# when all (non weak) references to it are gone.
!x = $&& (std:to_drop 10 {|| .drop_check = $true });

# Create a weakened reference to the value referred to by x:
!y = std:weaken x;

# Deref y gives you 10:
std:assert_eq $*y 10;

# The reference to 10 is removed and this means that the weak reference
# in y is invalidated and returns $n in future.
.x = $n;

# Deref y now gives you $n:
std:assert_eq $*y $n;

std:assert drop_check;

Operators

Arithmetics

  • +
  • -
  • *
  • /
  • %
  • ^

Comparison

  • ==
  • !=
  • <
  • >
  • <=
  • >=

Bitwise

  • &|
  • &
  • &^
  • <<
  • >>

Functions (part 2/2)

Function call composition

  • chaining
  • traditional () call syntax
  • ~ syntax
  • | syntax
  • || syntax

$[] || push 10 $[10] $[] || push 10 || push 20 $[10,20] !x = { push _1 _ }; $n $[] | x 10 | x 20 $[10,20]

  • [...] syntax

Control Flow - Returning

  • :lbl { ... } syntax and returning

WLambda uses labelled blocks for control flow, as returning from the current function would not be very helpful for the control flow in wlambda in case of conditional execution.

!some_func = \:outer {
    !x = 10;
# does stuff

    (x == 10) {
return :outer 20
    }

# more stuff that is not executed if x == 10.
}

Conditional Execution - if / then / else

WLambda has no if. Conditional execution is provided by the bool data type. As in WLambda everything can be called like a function, you can just pass other functions as arguments to $true and $false. If you pass a function as first argument to $true, it will be executed. If you pass a function as second argument to $false then that will be executed.

(10 == 10) { std:displayln "10 is 10" };         #=> prints "10 is 10"
(10 != 10) { std:displayln "10 is not 10" };     #=> doesn't print anything

!x = 20;

(x == 20) {
    std:displayln "x is 20";
} {
    std:displayln "x is 20";
}; # Do not forget the ";"!

Actually, as the values $true and $false can be called like any other function you may write it also like this, which is not the recommended syntax, but still works:

(10 == 10)[{ std:displayln "10 is 10" }];

!x = 21;
(x == 20)[{ std:displayln "x is 20" }, { std:displayln "x isn't 20" }]; #=> print "x isn't 20"

Iteration

WLambda has many ways to iterate:

  • Counting loop with range
  • While some condition is $true with while
  • Over the items in a vector with either for or by calling the vector with a function as first argument.
  • Over the items in a map with either for or by calling the map with a function as first argument.
  • Over the characters in a string with either for or by calling it with a function.
  • Over the bytes in a byte vector with either for or by calling it with a function.

for just iterates through the value and provides the individual items as first argument to the iteration function. But if you call the value with a function as first argument a mapping iteration is done. That means, the return value of the operation is a list with the return values of the iteration function. If you don't need that list you should use for.

Lexical Scope and Variable assignment

  • !x = y variable definition
  • .x = y assignments
  • !:ref x = y upvalue references
  • !:wref x = y weak upvalue references
  • !(x, y) = list / map destructuring assignments

Arithmetics

  • operator precedence syntax
  • prefix operator syntax

Modules

export


!expr = { _ + 30 };

!@export symbol = expr; # exports symbol with value of expr (a function)

import


!@import x = tests:test_mod; # prefixes everything from modixes with x:

std:assert ~ (x:symbol 10) == 40;

You can also skip the prefix:

!@import std;
!v = $[];
push v 10; push v 20;
std:assert_eq (str v) "$[10,20]";

Standard Library

std:shuffle rand_func vec

Shuffles the vec in place. The function rand_func needs to return a random 64 bit integer on each call. Here is an example:

!sm  = std:rand:split_mix64_new_from 1234;
!vec = $[1,2,3,4,5,6,7,8];
std:shuffle { std:rand:split_mix64_next sm } vec;

std:assert_eq (str vec) "$[2,1,7,4,8,5,3,6]";

std:copy vec_or_map

Makes a shallow copy of the given vector or map.

!a = $[1,2,3];
!b = std:copy a;
b.0 = 10;

std:assert_eq a.0 1;
std:assert_eq b.0 10;

std:sort [compare_fun] vec

Sorts the given vec in place. The comparison function compare_fun gets the two values a and b and needs to return -1 if a < b, 0 if a = b and 1 if a > b.

There are four functions that implement numeric and lexicographic ordering:

  • std:cmp:num:asc
  • std:cmp:num:desc
  • std:cmp:str:asc
  • std:cmp:str:desc

If no compare_fun is given, the ordering will be ascending and lexicographic vs. numeric will be chosen by the type of the a value (if it is an integer or float it will be numeric, otherwise lexicographic).

!v = $[$[1], $[-1], $[3]];
std:sort { std:cmp:num:desc _.0 _1.0 } v;

std:assert_eq v.0.0 3;
std:assert_eq v.1.0 1;
std:assert_eq v.2.0 -1;

std:displayln arg1 ...

This function writes a humand readable version of all the arguments (with a space inbetween) to the standard output. This means that:

std:displayln "foo"

Will just print foo and a newline.

If you need a less ambigous form, use std:writeln, which handles it's argument like written via std:str:write instead of str.

std:writeln arg1 ...

This function writes the WLambda representation of it's arguments (with a space inbetween) to standard output. This means that:

std:displayln "foo"

Will print "foo" and a newline.

See also the description of std:str:write.

If you need a more human readable form use std:displayln.

std:str:write arg

Returns the WLambda representation of the value arg as string.

Most values have the same represenation like a WLambda literal, but there are other values that don't have a literal representation.

Warning: Consider all values that don't have a fixed literal representation in the WLambda syntax as debug output that might change in future versions.

std:assert_eq (std:str:write "foo") $q|"foo"|;
std:assert_eq (std:str:write $none) $q|$n|;
std:assert_eq (std:str:write $[1,:a]) $q|$[1,:"a"]|;

std:eval code-string

Evaluates code-string in the current global environment and returns the generated value. If the code leads to any kind of evaluation error, an error object is returned.

std:assert_eq (std:eval "1 + 2") 3;
!:global X = 20;
std:assert_eq (std:eval "1 + X") 21;

std:assert bool [message]

Just a simple assertion function that panics if the first argument is not true. Returns the passed value if it is a true value. You can pass an optional message as second parameter.

std:assert $false; #=> Panic
std:assert 120;    #=> 120

std:assert_eq actual expected [message]

This function check if the actual value is equal to the expected value and panics if not. The optional message is passed in the panic for reference.

!x = 30 * 2;
std:assert_eq x 60 "30 * 2 == 60";

I/O

std:io:file:read_text filename

Opens the file filename and returns it's contents interpreted as UTF8 text as string.

std:io:file:write_safe "prelude_test.txt" "abcäöü";

!t = std:io:file:read_text "prelude_test.txt";
std:assert_eq t "abcäöü" "reading text from file works";

std:io:file:read filename

Opens the file filename and returns it's contents as byte buffer.

std:io:file:write_safe "prelude_test.txt" "abcäöü";

!t = std:io:file:read "prelude_test.txt";
.t = std:str:from_utf8 t;
std:assert_eq t "abcäöü" "reading binary from file works";

std:io:file:write_safe filename bytes-or-string

Creates a new file with the given filename but with a "~" appended and writes the contents into it. After successful write, it renames the file to the given filename.

std:io:file:append filename bytes-or-string

Opens the given filename in append mode and appends bytes-or-string to the end of the file.

Optional Standarf Library

serialization

std:ser:json data [no_pretty]

Serializes the data and returns a JSON formatted (and pretty printed) string. Optionally not pretty printed if no_pretty is a true value.

!str = std:ser:json $[1,2.3,${a=4}] $t;
std:assert_eq str "[1,2.3,{\"a\":4}]";

std:deser:json string

Deserializes the JSON formatted string into a data structure.

!data = std:deser:json ~ std:ser:json $[1,2.3,${a=4}];
std:assert_eq data.0 1;
std:assert_eq data.1 2.3;
std:assert_eq data.(2).a 4;

std:ser:csv field_delim row_separator escape_all table

This serializes the table as CSV with the given field_delim and row_separator. If escape_all is $true all fields will be put into '"'.

!csv_str =
    std:ser:csv
        ";" "|" $f
        $[ $[1,2,3,4,$q/foo"bar/],
           $[44,55],
           $[]]
    | std:displayln;

std:assert_eq csv_str $q/1;2;3;4;"foo""bar"|44;55||/;

std:assert_eq
    (std:ser:csv ";" "|" $f $[$[:a,$q/;/, $q/|/, $q/ /]])
    "a;\";\";\"|\";\" \"|";

std:deser:csv field_delim row_separator data

Parses the string data as CSV. With the field delimiter field_delim and the row_separator for the data rows.

!table = std:deser:csv ";" "\r\n" "foo;bar\r\nx;y\r\n";
std:assert_eq table.0.0 "foo";
std:assert_eq table.0.1 "bar";
std:assert_eq table.1.1 "y";

std:ser:msgpack data

Serializes the data and returns a msgpack bytes value.

std:assert_eq (std:ser:msgpack $b"abc") $b"\xC4\x03abc";

std:deser:msgpack bytes

Deserializes the msgpack bytes value into a data structure.

std:assert_eq (std:deser:msgpack $b"\xC4\x03abc") $b"abc";

regex

chrono

std:chrono:timestamp [format]

For the documentation of format please consule the chrono Rust crate documentation: chrono crate strftime format.

!year_str = std:chrono:timestamp "%Y";
std:displayln :XXXX ~ (year_str | int) == 2020;
std:assert ~ (year_str | int) == 2020;

!now_str = std:chrono:timestamp[];

hash

std:hash:fnv1a arg1 ...

Hashes all the arguments as FNV1a and returns an integer.

rand

std:rand:split_mix64_new

Initializes the sm_state from the current time (seconds) and returns it. The time is retrieved in seconds, so don't expect different seed states if you call this multiple times in the same wall clock second. The returned value is supposed to be passed to rand:split_mix64_next or rand:split_mix64_next_open01.

std:rand:split_mix64_new_from seed

Initializes the sm_state from the given seed and returns it. The returned value is supposed to be passed to rand:split_mix64_next or rand:split_mix64_next_open01.

std:rand:split_mix64_next sm_state [count]

Returns the count next integer values generated from the given sm_state.

std:rand:split_mix64_next_open01 sm_state [count]

Returns the count next float values (in an open [0, 1) interval) generated from the given sm_state.

Functions

core_symbol_table

Returns a SymbolTable with all WLambda core language symbols.

std_symbol_table

Returns a SymbolTable with all WLambda standard library language symbols.