#!/usr/bin/env lang :: module; // import module to current namespace :: _ = module_2; // import module to current namespace and use functions inside without namespace :: module_3 : func1 func2 func3; :: module_namespace = module_4; func = { @ => { %x := scan; ?? x == ''x'' => break; }; @ i < 10 => { inc i; }; @ %x : 1..10 => { print "Hello World!\n"; }; ?? abracadabbra < abracadabra_abracadabra || some_long_name == another_long_name &&. abracadabra-abracadabra < long_long_long_long_name => io.print x !! x < 0 => { x += 1; io.print y; } !!=> return (); } : example of function with optional arguments (without type annotation) : real type is 'A? 'A? -> 'A? sum 'a? 'b? = 'a & 'b =: %a? & %b? => a + b =: _ => null; : example that shows that default annotations are argument names (without ') @a is integer @b also integer sum_2 'a 'b = 'a + 'b; : this function can be used to calculate Fibonacci sequence elements : it is important is some algorithmic tasks : also this is example of function constraint @n is position in Fibonacci sequence ? 'n >= 0; fib 'n : @n Int -> Int = 'n =: 0 | 1 => 1 =: _ => fib ('n - 1) + fib 'n; func_2 = { %variant := x; %val | %err := f x; %lambda1 := \'x 'y => 'x + 'y; %lambda2 := \ => 3; variant =: 1 | 2 => "a" =: 3..10 => "b" =: 45 | 55 | x ?? x > 100 => "c" =: _ => "another variants"; // all var arrays are dynamic $array := [[x y z]]; array.push a; %x := maybe_something => do_something := _ => do_something_another; %x := Task @name "do something" @duration 123.1; // open optional: execute expression only if not null %x? := maybe_something => do_something; // open optional: return null to all outputs (all outputs should be optional values) %x? := maybe_something; // open optional: panic on null %x! := maybe_something; // open optional: return null to all outputs (all outputs should be optional values) maybe_something?; // open optional: panic on null maybe_something!; // open optional: if null then return default value (operator) %x := maybe_something ?| value; %y := Fruit @apple (); y =: Fruit @apple () => "apple" =: Fruit @orange () => "orange" =: Fruit @banana () => "banana"; %z := ( + ) 1 2; // tuple access %t := 1 & 2 & 3; print t.0; } : operator definition example ( - ) 'a 'b = 'a + neg 'b; test.something = { do_something a b c; } exec.something = { do_something a b c; } example.something = { do_something a b c; } Task = @name String & @duration Float; Fruit = @apple Unit | @orange Unit | @banana Unit; : function that takes array reference argument bubble_sort 'arr : <> Array['A] = { swap_occured := true; @ swap_occured => { swap_occured = false; @ %i : 0 .. 'arr.size => (?? 'arr[i] > 'arr[i + 1] => swap 'arr[i] 'arr[i + 1], swap_occured = true); }; } : bubble_sort with names instead of symbols bubble_sort_2 'arr : ref Array['A] = { var swap_occured := true; for swap_occured do { swap_occured = false; for let i : 0 .. 'arr.size do (if 'arr[i] > 'arr[i + 1] do swap 'arr[i] 'arr[i + 1], swap_occured = true); }; } : example of <> and generics. <> (in type definition) used to denote that this object allocated on heap : object allocated by unique reference by default <> TreeNode 'Key 'Value = & @key Key & @value Value & @left <> TreeNode['Key 'Value] & @right <> TreeNode['Key 'Value]; .new = do_something; // static methods .insert <> 'this 'key = do_something; // const methods .find 'this 'key = do_something; .delete <> 'this 'key = do_something; // var methods generic_type_name_expressions = { $x := TreeNode[Int Int].new; $y := std.Array[Int].new; } pipes_example = { expr |> func_1 a b |> func_2 c d |> print; // print (func_2 (func_1 expr a b) c d) print <| func_1 a b <| func_2 c d <| expr; // print (func_1 a b (func_2 c d expr)) } test_ref_access_precendence = { %x := <> arr[123]; } // by default constant arguments are used : constant arguments example, type - 'A 'B print_two 'a 'b = print 'a, print 'b; : example of reference args and comma operator swap 'a 'b : <> 'A <> 'A = %c := <- 'a, 'a := <- 'b, 'b := <- c; : previous example with automatic type deduction swap_2 <> 'a <> 'b = %c := <- 'a, 'a := <- 'b, 'b := <- c; : several outputs example scan_three : -> String -> String -> String = scan & scan & scan; : output by argument scan_to_variable 'a : -> String = 'a := scan; : consuming input example move_construct_task 'name 'duration : <- String <- Float -> Task = Task @name 'name @duration 'duration; : copy constructing, field annotations deduced arg_deduction_example 'name 'duration : <- String <- Float -> Task = Task 'name 'duration; : ord is fundamental typeclass #Ord[#Eq]; .is_less_then : Ord -> Bool; : function, that takes result argument result_example 'a! = 'a =: _? => print "value inside" =: _ => print "error inside"; : function, that returns result parse_number : Unit! = { %number_str := String.scan; %number! := Int.parse number_str; number.print; bring (); } : example of or_in and or_out usage for template operators (tuple input and tuple output) ( & ) --|-> 'a --|-> 'b <-|-- 'x <-|-- 'y = ('a := 'x) && ('b := 'y); : function, that return result ('!' not used on calls) : useful when tuples returned result_func! 'a 'b -> 'c -> 'd = ?? 'a == 0 => error "some error" !!=> ('c := 'a, 'd := 'b, ()); // (A & B & C) same to Tuple[A B C] tuple_argument_test 'x : (A & B & C) = do_something; // ((A1 & A2) | B | C) same to Variant[Tuple[A1 A2] B C] variant_argument_test 'x : ( (A1 & A2) | B | C) = do_something; literals_test = { %float_number_literal := 1.0f; %double_number_literal := 1.0; %int_literal := 1i; %long_literal := 1l; %index_literal := 1; %string_literal := ""; %unicode_string_literal := ""u; %char_literal := ''a''; %unicode_literal := ''↪''u; %bool_literal := true; %unit_literal := (); %null_literal := null; } array_argument_test 'x : [[ Int ]] = do_something; functional_arguments_test 'x 'y : (( Int -> Int )) (( Float <- Float -> Float )) = do_something;