Table of Contents

1 Introduction

1.1 Command Line Interpreter

1.2 Hello World

1.3 Main Wafl Concepts

1.4 Introduction to the Types

2 Program Structure

2.1 Program Is an Expression

2.2 Comments

2.3 Tuples

2.4 Local Definitions

2.5 Function Definition

2.6 Named Expression Definition

2.7 No Variables

2.8 The Order of the Definitions

2.9 Conditional Expression if

2.10 Conditional Expression switch

2.11 Recursion

2.12 Libraries

3 Programming With Functions

3.1 Strict Type Checking

3.2 Automatic Type Inference

3.3 Polymorphism

3.4 Higher Order Functions

3.5 Partial Application

3.6 Lambda Functions

3.7 Lambda Closures

3.8 Operators as Functions

3.9 Dot Operator

3.10 Explicit Computation State

3.11 Cached Functions

4 Primitive Types

4.1 Literals

4.2 Operators

4.3 Conversion Functions

4.4 Integer Functions

4.5 Float Functions

4.6 String Functions

5 List Type

5.1 List Literals

5.2 Basic List Functions

5.3 Basic List Processing

5.4 Advanced List Processing

5.5 More List Functions

5.6 Functions map and zip

5.7 Functions foldr, foldl and fold

5.8 Functions filter, find and filterMap

5.9 Functions forall and exists

5.10 Functions count and countRep

5.11 Functions sort and sortBy

5.12 Functions in and contains

5.13 Lazy Lists

6 Structured Types

6.1 Array Type

6.2 Map Type

6.3 Tuple Type

6.4 Record Type

7 Elements of Wafl Library

7.1 Program Control

7.2 File Reading

7.3 File Writing

7.4 File Operations

7.5 Directory Operations

7.6 Regex Functions

7.7 Command Line

7.8 Web and HTTP Functions

7.9 Wafl to JSON

7.10 Wafl Program Evaluation

8 Parallelization

8.1 Wafl and Parallelization

8.2 Parallel Functions

9 Core Library Reference

9.1 Main Library

9.2 Command Line Library

9.3 Web Library

9.4 XML Library

9.5 Drawing Library (SDL)

9.6 Timer Library

9.7 Edlib Library

10 Command Line Reference

10.1 Command Line Options

10.2 Configuration Files

10.3 ANSI Control Codes

11 Advanced

11.1 JIT

11.2 Wafl Binary Libraries

12 More Content…

12.1 Soon…

 

 

Last update: 29.01.2025.

Wafl

Wafl

Tutorial / 7 - Elements of Wafl Library

Open printable version

7 Elements of Wafl Library

7.1 Program Control

Side Effects

Command line programs often require some output to describe the actions of the program, or read and write some files, without all of this being explicitly part of the result that the program computes. Such things are called side effects. They do not exist in pure functional languages, but they can be of great use in command-line programs and scripts.

Some of the functions presented in Command Line Library create side effects. For example, the input function and all echo functions. These functions focus on communication, and controlling the side effects is their secondary task. There are two functions whose main task is to control the side effects: return and aside.

Function / Type and Description

return

('1 * '2 -> '2)
Evaluates both arguments, discards the 1st result and returns 2nd one.

aside

('1 * ('1 -> '2) -> '1)
Applies 2nd arg. to 1st, discards the result and returns 1st arg:
    aside(x,fn) == fn(x).return(x)

The function return has two arguments. It evaluates both in the specified order and returns the second one. It is assumed that the first argument only has a side effect role and its value is discarded.

It can be misleading to think of this function in the usual form return(x,y), as it is normally used in a different way. It is used almost exclusively in the form ...exp... .return(y), where the expression ...exp... is evaluated and discarded and then y is evaluated and returned. Only the side effects of the expression ...exp... are important, while the result is discarded.

"Good morning!"
.return( "Good afternoon!" )

Good afternoon!

The function return is useful, for example, after writing a file, traversing a directory and some other operations with side-effects, when there is no need to return the specific results. For example, the following expression performs some processing, then discards the current result and returns the message “OK” as confirmation that the program has finished:

... some processing ...
.echoTxt('--------\n')
.return( "OK" )

...whatever the processing output is...
--------
OK

"Good morning!"
.echoLn()
.echoTxt( '-------------------\n' )
.return( "Good afternoon!" )

Good morning!
-------------------
Good afternoon!

The function return is not always the best solution, as it not only discards the result of the first argument, but may also discard an error report. You should therefore use it with caution.

The function aside is similar to return - it evaluates two arguments in the specified order, but then returns the first and discards the second. It assumes that the current result is still needed, but performs some intermediate processing. It is typically used to output a report on the current progress or result status, as in the following example:

"Good morning!"
.aside(\x: 
    ("Before saying: \"" + x + "\", bring a cup of coffee first!").echoLn()
)

Before saying: "Good morning!", bring a cup of coffee first!
Good morning!

In some simple cases, it is often sufficient (and better) to use echo functions (the echoFn is perfect in the previous example), but if the reporting involves a file creation or a database update, then aside is a much better solution.

The function aside can be used to prepare some temporary resources for processing or to perform a cleanup after the processing. For example, consider the following code:

... begin ...
.aside(\x: ... create some tmp files ... )
... processing ...
.aside(\x: ... delete tmp files ... )
... finalize ...

Iteration Functions

Having discussed list processing, we now have a broader picture of common programming techniques in functional programming languages. The computation is implicitly controlled by some higher order functions and by the processed data itself. This approach is general and flexible enough to solve practically any problem. In some cases, however, the creation and processing of additional lists burdens the computation without this really being necessary.

For thos reason, the Wafl core library contains some so-called iterative functions. Iterative functions are used as a tool to control the iterative computation, but based on integers and conditions, rather than on sequences.

Function / Type and Description

iterate

('1 * Int * Int * ('1 * Int -> '1) -> '1)
Left associative folding of specified integers range:
    iterate(zero,2,4,fn) = fn(fn(fn(zero,2),3),4)
        = zero.fn(2).fn(3).fn(4)
        = (2..4).foldl(fn,zero)

iterateBy

('1 * Int * Int * Int * ('1 * Int -> '1) -> '1)
Left associative folding of specified integers range by step:
    iterateBy(zero,2,6,2,fn) = fn(fn(fn(zero,2),4),6)
        = zero.fn(2).fn(4).fn(6)
        = [2,4,6].foldl(fn,zero)

repeatUntil

('1 * ('1 -> '1) * ('1 -> Bool) -> '1)
Repeats the function evaluation until the condition is met:
    repeatUntil(x,fn,cond) =
        if cond(x) then x
        else fn(x).repeatUntil(fn,cond)

The function iterate(zero,from,to,fn) computes a left associative folding of the specified integer range. It is functionally equivalent to imperative for-loop, like the next one in C++:

auto result = zero;
for( int i=from; i<=to; i++ )
    result = fn( result, i );
return result;

The function iterate(zero,from,to,fn) is equivalent to expression (from..to).foldl(fn,zero), but performs the computation without creating the list from..to, so that it is more efficient. If the range is in descending order, the negative step is used:

{#
    iterate( '#', 1, 10, \s,x: s + '-' + x.asString() ),
    iterate( '#', 10, 1, \s,x: s + '-' + x.asString() ),
    (1..10).map(sum(1,_)),
    (1..10).map(fact)
#}
where {
    sum(n,m) = iterate( 0, n, m, operator+ );
    fact(n) = iterate( 1, 1, n, operator* );
}

{# '#-1-2-3-4-5-6-7-8-9-10', '#-10-9-8-7-6-5-4-3-2-1', [1, 3, 6, 10, 15, 21, 28, 36, 45, 55], [1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800] #}

The function iterateBy(zero,from,to,step,fn) is a more general form of iterate. If iterate is used, the step is always 1 or -1. With iterateBy, the step may be any integer.

{#
    iterateBy( '#', 1, 10, 2, \s,x: s + '-' + x.asString() ),
    iterateBy( '#', 10, 1, -3, \s,x: s + '-' + x.asString() )
#}

{# '#-1-3-5-7-9', '#-10-7-4-1' #}

The function repeatUntil(x,fn,cond) controls the iteration based on the given condition. It repeats the iterative transformation of x until the condition is fulfilled. Again, it can be useful to describe this in an imperative way:

auto result = x;
while(!cond(result))
    result = fn(result);
return result;

In the next example, the given number is multiplied by itself until the result is greater than or equal to 1000:

(2..10).map( enlarge )
where {
    enlarge(n) = n.repeatUntil(
        operator*(n,_),
        operator>=(_,1000)
    );
}

[1024, 2187, 1024, 3125, 1296, 2401, 4096, 6561, 1000]

7.2 File Reading

Function / Type and Description

fileRead

(String -> String)
Reads entire file to a string.

fileReadPart

(String * Int * Int -> String)
Reads a part of the file, from given 0-based position and with given length in bytes:
    fileReadPart( fname, pos, bytelen )

fileSize

(String -> Int)
Returns the file size.

The fileRead(filepath) function reads the file and returns its content as a string. The entire file is read, regardless of its size. This approach should not be used for very large files due to the high memory consumption.

For very large files, the function fileReadPart(filepath,pos,bytelen) should be used. It reads a part of the file that starts at the given position pos (in bytes) and has the given length bytelen.

The function fileSize(filepath) returns the size of the specified file.

fileRead( 'src/txt/en/title.md' )


# Wafl Tutorial

*Wafl* is a strongly typed functional programming language, with implicit type inference. It was originally designed as an experimental application of FP languages in web development. A few years later, however, Wafl became a simple and very fast scripting language, with a simple and efficient interface to databases.

The Wafl Tutorial introduces the language constructions, the use of the command line interpreter, elements of the core library and many examples.

Welcome to *Wafl*!

*Saša Malkov*

fileReadPart( 'src/txt/en/title.md', 100, 100 )

inference. It was originally designed as an experimental application of FP languages in web developm

fileSize( 'src/txt/en/title.md' )

530

7.3 File Writing

Function / Type and Description

fileWrite

(String * String -> String)
Writes string to a file and truncates old content:
    fileWrite( fname, content )

fileWriteAppend

(String * String -> String)
Writes string to a file by appending to the file end.
    fileWriteAppend( fname, content )

fileWriteTo

(String * String -> String)
Writes string to a file and truncates old content:
    fileWriteTo( content, fname )

fileTruncate

(String -> Bool)
Truncates a file. Returns false if truncate fails or file does not exist.

The function fileWrite(filename,s) writes the given character string s to the file and discards the old file contents, if present. The function fileWriteTo(s,filename) does the same, only with the order of the arguments changed. It is good to have both functions because of the dot-syntax.

If an empty string s is specified, the file is truncated. If there is no such file, a new empty file is created.

The functions fileWriteAppend and fileWriteAppendTo have the same arguments, but append the given string s to the end of the file and do not discard the previous file contents.

Each of the functions returns the string s as a result.

The function fileTruncate truncates the file. If the file does not exist, a new empty file is created. This is exactly the same behavior as when writing an empty string with fileWrite or fileWriteTo.

{#
    fileWrite( "tmp.txt", "One sentence. " ),
    fileWrite( "tmp.txt", "Another sentence. " )
#}

{# 'One sentence. ', 'Another sentence. ' #}

fileRead( 'tmp.txt' )

Another sentence. 

{#
    fileWrite( "tmp.txt", "One sentence. " ),
    fileWriteAppend( "tmp.txt", "Another sentence. " )
#}

{# 'One sentence. ', 'Another sentence. ' #}

fileRead( 'tmp.txt' )

One sentence. Another sentence. 

7.4 File Operations

Function / Type and Description

fileExists

(String -> Bool)
Checks whether a file with the given name exists.

fileOrDirExists

(String -> Bool)
Checks whether a file or a directory with the given name exists.

fileDelete

(String -> Bool)
Deletes a file.

fileNewTempName

( -> String)
Generates a new temporary file name.

The functions fileExists and fileOrDirExists check and return whether a file or directory with the specified name exists.

The function fileExists checks the files and if it returns true, then there is a file with the given name. It can be used to check before reading or deleting a file.

{#
    fileExists( 'tmp.txt' ),
    fileExists( 'tmp2.txt' ),
    fileDelete( 'tmp.txt' ),
    fileExists( 'tmp.txt' )
#}

{# true, false, true, false #}

The function fileOrDirExists checks both the files and directories and returns true if there is a file or a directory with the given name. It can be used to check before creating a file or a directory.

The function fileNewTempName() returns a possible name for a new temporary file. The file name is located in the directory for temporary files, which depends on the respective platform. When the program is terminated, all files with the names returned by this function are deleted.

7.5 Directory Operations

Function / Type and Description

dirCreate

(String -> Bool)
Creates a directory.

dirDelete

(String -> Bool)
Deletes a directory, if it is empty

dirExists

(String -> Bool)
Checks whether a directory with the given name exists.

dirFiles

(String -> List[String])
Returns the list of files that fulfill the given filter.

dirSubdirs

(String -> List[String])
Returns the list of subdirs that fulfill the given filter.

fileOrDirExists

(String -> Bool)
Checks whether a file or a directory with the given name exists.

The functions dirFiles(filter) and dirSubdirs(filter) return lists of files and directories that match the given filter. The paths returned are relative to the current working directory.

"Directories:\n  "
+ dirSubdirs( '*' ).strJoin('\n  ')
+ "\nFiles:\n  "
+ dirFiles( '*' ).strJoin('\n  ')

Directories:
  .vscode
  bld
  code
  design
  lib
  resources
  src
Files:
  bldall.cmd
  bldsite.cmd
  pandocHtml.cmd
  pandocPdf.cmd
  prepmd.cmd
  run_local_http_server.cmd
  site.cmd
  test.wafl
  todo.notes.txt
  Tutorial - Site Version.lnk
  Tutorial - Standalone Version.lnk
  WaflTutorial.md

The function dirExists is similar to fileExists and fileOrDirExists, but it only checks whether a directory with the specified name exists. It can be used before creating, deleting or traversing a directory.

7.6 Regex Functions

The regex support in Wafl uses the ECMAScript syntax for regular expressions, as defined and implemented in the C++ standard library from C++11.

By default, all quantifiers are greedy (they match as many characters as possible). This can be overridden to ungreedy (match as few characters as possible) by adding a question mark ? after the quantifier.

Match the Entire String

Function / Type and Description

regexMatch

(String * String -> Bool)
Checks whether a string matches given regular expression.

regexMatchI

(String * String -> Bool)
Checks whether a string matches given regular expression. Ignores upper and lower case.

The regex matching functions regexMatch(s,r) and regexMatchI(s,r) check whether the given string s matches the given regular expression r. The match is performed for the entire string s. The only difference is that regexMatch(s,r) ignores upper and lower case.

{#
    s.regexMatch("ab.*AB"),
    s.regexMatch(".*ab.*AB.*"),
    s.regexMatch(".*ab.*cd.*"),
    s.regexMatch(".*AB.*ab.*"),
    s.regexMatchI(".*AB.*ab.*")
#}
where {
    s = "abcabcABCABC";
}

{# false, true, false, false, true #}

Match the Substrings

Function / Type and Description

regexPos

(String * String -> Int)
Finds the first regex matching position in the given string.

regexPosI

(String * String -> Int)
Finds the first regex matching position in the given string. Ignores upper and lower case.

regexPosAll

(String * String -> List[Int])
Finds all regex matching positions in the given string.

regexPosAllI

(String * String -> List[Int])
Finds all regex matching positions in the given string. Ignores upper and lower case.

The regex functions regexPos(s,r) and regexPosI(s,r) search for the first position of a substring of the given string s that matches the given regular expression r.

{#
    s.regexPos("ab.*AB"),
    s.regexPos("ab.*cd"),
    s.regexPos("AB.*ab"),
    s.regexPosI("AB.*ab")
#}
where {
    s = "abcabcABCABC";
}

{# 0, -1, -1, 0 #}

The regex functions regexPosAll(s,r) and regexPosAllI(s,r) search for the starting positions of all substrings of the given string s that match the given regular expression r.

{#
    s.regexPosAll("ab.*AB"),
    s.regexPosAll("ab.*cd"),
    s.regexPosAll("AB.*ab"),
    s.regexPosAllI("AB.*ab"),
    s.regexPosAllI("AB.*?ab"),
    s.regexPosAllI("a.*c"),
    s.regexPosAllI("a.*?c")
#}
where {
    s = "abcabcABCABC";
}

{# [0], [], [], [0], [0, 6], [0], [0, 3, 6, 9] #}

Replace the Substrings

Function / Type and Description

regexReplace

(String * String * String -> String)
Replaces all matching of a regex with the given string.

regexReplaceI

(String * String * String -> String)
Replaces all matching of a regex with the given string. Ignores upper and lower case.

The regex functions regexReplace(s,r,x) and regexReplaceI(s,r,x) search for the positions of all substrings that match the given regular expression r, and replace them with the given string x.

{#
    s.regexReplace("ab.*AB", "#"),
    s.regexReplace("ab.*?AB", "#"),
    s.regexReplace("ab.*cd", "#"),
    s.regexReplace("AB.*ab", "#"),
    s.regexReplaceI("AB.*ab", "#"),
    s.regexReplaceI("AB.*?ab", "#"),
    s.regexReplaceI("a.*c", "#"),
    s.regexReplaceI("a.*?c", "#")
#}
where {
    s = "abcabcABCABC";
}

{# '#C', '#CABC', 'abcabcABCABC', 'abcabcABCABC', '#C', '#c#C', '#', '####' #}

If it is necessary to preserve a part of the found substring, you can use the capture groups. A capture group is a part of the regular expression enclosed in parentheses, except when the first character in the parentheses is a question mark. In the replacement string x, you can use $n to copy a capture group, where n is an integer 1-based index of the corresponding capture group. In the following example, the capture groups are used to insert a dash - between two lower case letters:

{#
    s.regexReplace("([a-z])([a-z])", "$1-$2"),
    s.regexReplace("([a-z])([a-z])", "$1-$2")
     .regexReplace("([a-z])([a-z])", "$1-$2")
#}
where {
    s = "abcabcABCABC";
}

{# 'a-bc-ab-cABCABC', 'a-b-c-a-b-cABCABC' #}

Function / Type and Description

regexSearch

(String * String -> List[String])
Searches for the regex matching in the given string.

regexSearchI

(String * String -> List[String])
Searches for the regex matching in the given string. Ignores upper and lower case.

regexSearchAll

(String * String -> List[List[String]])
Searches for all regex matchings in the given string.

regexSearchAllI

(String * String -> List[List[String]])
Searches for all regex matchings in the given string. Ignores upper and lower case.

The regex search functions regexSearch(s,r) and regexSearchI(s,r) search for the first substring of the given string s that matches the given regular expression r and return all matched sub-elements. The returned value is a list of strings. The first element of the list is the complete matched substring, and the following elements correspond to the sub-patterns (capture groups) of the regular expression.

The following example searches for the pattern <name>=<n>:

{#
    s.regexSearch("([a-z]+)\\s*=\\s*([0-9]+)")
#}
where {
    s = "a=12 ;bcd = 24; ef =354";
}

{# ['a=12', 'a', '12'] #}

The first element of the returned list is the first matching substring. The second element is the corresponding part name (the first part of the regular expression enclosed in the parentheses ([a-z]+)), and the third element is the corresponding part n (the second part of the regular expression enclosed in the parentheses ([0-9]+)).

The functions regexSearchAll and regexSearchAllI do the same, but for all matching substrings. The result is therefore not a single list, but a list of string lists - one list for each matching substring. The elements of the lists are the same as in the result of the regexSearch function:

{#
    s.regexSearchAll("([a-z]+)\\s*=\\s*([0-9]+)")
#}
where {
    s = "a=12 ;bcd = 24; ef =354";
}

{# [['a=12', 'a', '12'], ['bcd = 24', 'bcd', '24'], ['ef =354', 'ef', '354']] #}

7.7 Command Line

The functions for command line support are specific to the command line Wafl interpreter. They are not normally available in other versions. The main purpose is to support the read and write operations of the command line terminal.

7.7.1 Program Arguments

The command line program interpreter supports the command line program arguments. There are some functions and special operators for working with command line arguments:

Function / Type and Description

$*

List[String]
Returns the list of command line arguments.

$#

Int
Returns a number of command line arguments.

$ A

(Int -> String)
Return a command line argument:
    $1 = cmdLineArgs()[1]

cmdLineArgs

( -> List[String])
Return a list of command line arguments.

cmdLineArgsCount

( -> Int)
Return a number of command line arguments.

The constant operator ‘$*’ is used to get the list of all command line arguments. The synonym, in the form of a function, is the function cmdLineArgs(). For example, if a program is started with the following command:

clwafl program.wafl a b c "abcde"

both $* and cmdLineArgs() return the following list:

['program.wafl', 'a', 'b', 'c', 'abcde']

The number of arguments can be computed as the size of the list of command line arguments (size($*)) or by using the constant operator $#, or its synonym function cmdLineArgsCount().

7.7.2 Program Result

Command line programs return an integer code to the caller (operating system or an application). If everything is OK, console programs are expected to return zero. In the event of an error, the programs return some program-specific positive values.

The function cmdSetExitCode(s,code) sets the program exit code to the specified integer code and returns s.

Function / Type and Description

cmdSetExitCode

('1 * Int -> '1)
Set program exit code to second argument and return the first one.

if $# > 1 
then $1 
else "No argument" .cmdSetExitCode(1)

No argument

7.7.3 User Interaction

Command Line Output

The output to the command line terminal is provided by the echo functions.

Function / Type and Description

echo

('1 -> '1)
Write the argument’s string representation to the console and return the argument:
    echo(x) == echoTxt( x, x.asString() )

echoLn

('1 -> '1)
Write the argument’s string representation and new line to the console and return the argument:
    echoLn(x) == echoTxt( x, x.asString() + '\n' )

echoTxt

('1 * String -> '1)
Write the second argument to the console and return the first argument.

echoFn

('1 * ('1 -> String) -> '1)
Apply the function to the 1st arg. and write the result to the console:
    echoFn( x, fn ) == echoTxt( x, fn(x) )

Each of the echo functions outputs something to the standard console output and returns its first argument.

The function echo(x) outputs the given value x converted to a string and returns the original value x. The function echoLn(x) does the same, but outputs an additional new line symbol at the end.

"This is a string"
.echo()
.echoLn()

This is a stringThis is a string
This is a string

The functions echoTxt and echoFn write some other strings to the command line output, but return the first argument in the same way as echo and echoLn. The function echoTxt(x,s) writes s and returns x. The function echoFn(x,fn) writes fn(x) and returns x:

"This is a string"
.echoTxt("Output from echoTxt\n")
.echoFn(\x: 'Output "' + x + '" from echoFn\n' )

Output from echoTxt
Output "This is a string" from echoFn
This is a string

Command Line Input

Function / Type and Description

input

(String -> String)
Write a string to the console, wait for input and return it.

The function input(s) writes the given string s to the command line output, waits for the user to enter a line into the console, and returns the entered string.

"Hello "
+ input( "What is your name? " )
+ "!"
What is your name? Marvin
Hello Marvin!

7.7.4 Shell Command Execution

Function / Type and Description

cmdExecute

(String -> String)
Execute the command in the active console and return the result.

cmdShellExecute

(String -> String)
Open new shell, execute the command in it and return the result.

cmdLastError

( -> Int)
Get integer code of last command status.

The functions cmdExecute(cmd) and cmdShellExecute(cmd) execute the given shell command string and return the results. They return the entire command output as a result. Both functions support the console input. The difference between the two functions is that cmdShellExecute sends the entire output to the console output, while cmdExecute outputs just a single lines one over another.

The function cmdLastError() returns the exit code of the last shell command executed. As usual, if everything is OK, it returns zero.

7.8 Web and HTTP Functions

The HTTP and web functions of the Wafl library are divided in two parts:

  • The Web Functions should only be used in Web applications, but have a defined regular behavior in other environments.
  • The Universal HTTP Functions work in any environment.

Universal HTTP Functions

Function / Type and Description

httpGetSize

(String -> Int)
Get WWW content length using HTTP/HTTPS HEADER method.[Deprecated. Use ‘Curl’ library.]

httpGet

(String -> String)
Get WWW content using HTTP/HTTPS GET method.[Deprecated. Use ‘Curl’ library.]

httpGet_callback

(String * (Int * Int -> Int) -> String)
Get WWW content using HTTP/HTTPS GET method, with progress callback[Deprecated. Use ‘Curl’ library.]

The httpGet(uri) function sends a GET HTTP request with a given uri, waits for a response and returns the content of the response. It can be used for both HTTP and HTTPS requests.

httpGet( 'http://www.informatics.rs/~smalkov/wafl/index.html' )
.size()

0

The function httpGetSize(uri) sends a HEADER HTTP request with a given uri, waits for a response and returns the reported size of the response content. It can be used for both HTTP and HTTPS requests. If a server does not respond to the HEADER request, the function returns -1. If a server responds to the request but returns an invalid header or a header without content size information, the function returns -2.

httpGetSize( 'http://www.informatics.rs/~smalkov/wafl/index.html' )

-1

The httpGet_callback(uri,fn) function sends a GET HTTP request with a given uri, uses the fn function of type (Int * Int -> Int) to process intermediate callbacks, waits for a response and returns the reported response content. The result value should be the same as in the case of httpGet. The function fn(received,expected) can perform some intermediate processing, such as progress reporting. The argument received is the total number of bytes received, and the argument expected is the total number of bytes expected. The expected should match the result of the httpGetSize(uri) and can be a negative value if the server does not deliver the expected size.

httpGet_callback( 
    'http://www.informatics.rs/~smalkov/wafl/index.html',
    \r,t: t.echoTxt( r.asString() + ' / ' + t.asString() + '\n')
)
.size()

0

httpGet_callback( 
    'http://poincare.matf.bg.ac.rs/~smalkov/images/h2.png',
    \r,t: t.echoTxt( r.asString() + ' / ' + t.asString() + '\n')
)
.size()

1161 / 7024
7024 / 7024
7024

Web Functions

Function / Type and Description

Form

( -> Map[String][String])
Get form variable set.

FormValue

(String -> String)
Get value of a given form variable.

Session

( -> Map[String][String])
Get session variable set.

SessionValue

(String -> String)
Get value of a given session variable.

Service

( -> Map[String][String])
Get service variable set.

ServiceValue

(String -> String)
Get value of a given service variable.

The functions Form(), Session() and Service() return the corresponding web variable sets - the current form content received from a client, the current set of session variables and the current service configuration. The functions FormValue(varname), SessionValue(varname) and ServiceValue(varname) return the value of a variable with the given variable name.

Function / Type and Description

httpHost

( -> String)
Get HTTP host for current request.

httpPathInfo

( -> String)
Get HTTP path info for current request.

httpScript

( -> String)
Get HTTP script for current request.

The functions httpHost(), httpPathInfo() and httpScript() return the corresponding parts of the currently processed URI.

Function / Type and Description

ask

(String -> Map[String][String])
Ask a question by sending the given page content to the client. Returns the next client’s request.

answerAction

( -> String)
Automatic action URI generator for forms in questions.

The ask(pageContent) function sends the given page content to the client and waits for the returned answer. All links and form actions on the page that begin with a relative link generated by answerAction(), represent the alternative answers for the given page and return to this specific function. The answerAction() function returns a result that identifies the specific current program evaluation so that the program can continue after an appropriate answer is received from the client.

7.9 Wafl to JSON

Convert Any Value to JSON

Wafl has two functions for exporting Wafl values to JSON.

Function / Type and Description

toJSON

('1 -> String)
Converts a value to a string in JSON format.

toFmtJSON

('1 -> String)
Converts a value to a string in pretty JSON format.

Both functions can be applied to any Wafl value type. The function toJSON(x) converts the value x into the JSON format in the as compact a form as possible. This is useful if the exported string only needs to be processed by machine.

The function toFmtJSON(x) does essentially the same thing, but exports the value in a better formatted JSON format. This is better if the exported string needs to be processed by humans.

(1..5).map(\n:{
    n: n, 
    s: 's'+n$, 
    t: {# n, 's'+n$ #}
})
.toJSON()

[{'n':1,'s':'s1','t':[1,'s1']},{'n':2,'s':'s2','t':[2,'s2']},{'n':3,'s':'s3','t':[3,'s3']},{'n':4,'s':'s4','t':[4,'s4']},{'n':5,'s':'s5','t':[5,'s5']}]

(1..5).map(\n:{
    n: n, 
    s: 's'+n$, 
    t: {# n, 's'+n$ #}
})
.toFmtJSON()

[ {
    'n': 1,
    's': 's1',
    't': [
       1,
       's1'
    ]
 }, {
    'n': 2,
    's': 's2',
    't': [
       2,
       's2'
    ]
 }, {
    'n': 3,
    's': 's3',
    't': [
       3,
       's3'
    ]
 }, {
    'n': 4,
    's': 's4',
    't': [
       4,
       's4'
    ]
 }, {
    'n': 5,
    's': 's5',
    't': [
       5,
       's5'
    ]
 } ]

7.10 Wafl Program Evaluation

Function / Type and Description

cmdWafl

(String * List[String] -> String)
Run Wafl program file in a command line shell with given arguments and return the result. All arguments are passed to Wafl program. No arguments apply to interpreter. The output is redirected to the caller’s output stream.

cmdWaflSrc

(String * List[String] -> String)
Run Wafl program source in a command line shell with given arguments and return the result. All arguments are passed to Wafl program. No arguments apply to interpreter. The output is redirected to the caller’s output stream.

cmdWaflX

(String * RecordX[]['1] -> String)
Run Wafl program file in a command line shell with given options and return the result. Options are specified as a record fields:
    cmdLineArgs - the list of command line arguments to pass
        to the program (List[String]);
        coutFile - the full filename of the output redirection file;
        if '*null*' is specified, output is discarded;
        if empty string is specified (default),
        the caller's output stream is used .

These functions carry out the evaluation of Wafl programs. The function cmdWafl(prgpath,args) evaluates a Wafl program in the specified file. The function cmdWaflSrc(src,args) evaluates the Wafl program written in the string. Both functions send the specified arguments as command line arguments to the evaluated program and return the program output and the result as a return value.

cmdWaflSrc('2+3',[])

5

"A controlled error:\n" 
+ cmdWaflSrc( 'an error',[])

A controlled error:
--- Loading from command line
Parser error
    Unexpected text at the end of the file! [err 1201:6]
    Line 1: an error
           ___/
--- End loading from command line

Each Wafl program evaluation is performed in a separate evaluation environment, but in the same process. This means that most errors do not propagate to the parent program (the one in which one of these functions is used), but if the memory usage becomes too high or the process fails, this can have an impact on the parent program.

It is even possible that such an evaluated program evaluates another Wafl program:

cmdWaflSrc( 'cmdWaflSrc("2+3",[])',[])

5

Wafl Home            Downloads            Wafl Tutorial v.0.6.8 © 2021-2025 Saša Malkov            Open printable version