From 35a782afe7d8b74beb68bd07e2854c0ddd4e448d Mon Sep 17 00:00:00 2001 From: daanx Date: Wed, 14 Feb 2024 22:26:10 -0800 Subject: [PATCH] update for v3.1.0 --- doc/book.html | 5660 +++++++++++++++++++++++++++- doc/index.html | 1464 ++++++- doc/std_core-source.html | 264 +- doc/std_core.html | 128 +- doc/std_core_bool-source.html | 59 +- doc/std_core_bool.html | 36 +- doc/std_core_char-source.html | 117 +- doc/std_core_char.html | 48 +- doc/std_core_console-source.html | 87 +- doc/std_core_console.html | 14 +- doc/std_core_debug-source.html | 90 +- doc/std_core_debug.html | 26 +- doc/std_core_delayed-source.html | 60 +- doc/std_core_delayed.html | 6 +- doc/std_core_either-source.html | 36 +- doc/std_core_either.html | 20 +- doc/std_core_exn-source.html | 124 +- doc/std_core_exn.html | 46 +- doc/std_core_hnd-source.html | 927 ++++- doc/std_core_hnd.html | 34 +- doc/std_core_int-source.html | 370 +- doc/std_core_int.html | 148 +- doc/std_core_list-source.html | 545 ++- doc/std_core_list.html | 168 +- doc/std_core_maybe-source.html | 92 +- doc/std_core_maybe.html | 42 +- doc/std_core_order-source.html | 55 +- doc/std_core_order.html | 26 +- doc/std_core_show-source.html | 76 +- doc/std_core_show.html | 22 +- doc/std_core_sslice-source.html | 328 +- doc/std_core_sslice.html | 82 +- doc/std_core_string-source.html | 228 +- doc/std_core_string.html | 78 +- doc/std_core_tuple-source.html | 71 +- doc/std_core_tuple.html | 20 +- doc/std_core_types-source.html | 531 ++- doc/std_core_types.html | 122 +- doc/std_core_undiv-source.html | 33 +- doc/std_core_undiv.html | 8 +- doc/std_core_unsafe-source.html | 57 +- doc/std_core_unsafe.html | 18 +- doc/std_core_vector-source.html | 210 +- doc/std_core_vector.html | 36 +- doc/std_num_ddouble-source.html | 1283 ++++++- doc/std_num_ddouble.html | 136 +- doc/std_num_decimal-source.html | 454 ++- doc/std_num_decimal.html | 86 +- doc/std_num_float64-source.html | 1008 ++++- doc/std_num_float64.html | 322 +- doc/std_num_int32-source.html | 570 ++- doc/std_num_int32.html | 250 +- doc/std_num_int64-source.html | 552 ++- doc/std_num_int64.html | 248 +- doc/std_num_random-source.html | 140 +- doc/std_num_random.html | 50 +- doc/std_os_dir-source.html | 87 +- doc/std_os_dir.html | 20 +- doc/std_os_env-source.html | 140 +- doc/std_os_env.html | 48 +- doc/std_os_file-source.html | 52 +- doc/std_os_file.html | 8 +- doc/std_os_flags-source.html | 350 +- doc/std_os_flags.html | 76 +- doc/std_os_path-source.html | 304 +- doc/std_os_path.html | 98 +- doc/std_os_readline-source.html | 38 +- doc/std_os_readline.html | 6 +- doc/std_os_task-source.html | 90 +- doc/std_os_task.html | 18 +- doc/std_text_parse-source.html | 219 +- doc/std_text_parse.html | 80 +- doc/std_text_regex-source.html | 207 +- doc/std_text_regex.html | 44 +- doc/std_text_unicode-source.html | 251 +- doc/std_text_unicode.html | 28 +- doc/std_time_astro-source.html | 371 +- doc/std_time_astro.html | 38 +- doc/std_time_calendar-source.html | 514 ++- doc/std_time_calendar.html | 86 +- doc/std_time_calendars-source.html | 335 +- doc/std_time_calendars.html | 18 +- doc/std_time_chrono-source.html | 80 +- doc/std_time_chrono.html | 18 +- doc/std_time_date-source.html | 276 +- doc/std_time_date.html | 100 +- doc/std_time_duration-source.html | 156 +- doc/std_time_duration.html | 76 +- doc/std_time_format-source.html | 326 +- doc/std_time_format.html | 22 +- doc/std_time_instant-source.html | 467 ++- doc/std_time_instant.html | 106 +- doc/std_time_locale-source.html | 115 +- doc/std_time_locale.html | 32 +- doc/std_time_parse-source.html | 206 +- doc/std_time_parse.html | 6 +- doc/std_time_time-source.html | 488 ++- doc/std_time_time.html | 192 +- doc/std_time_timer-source.html | 66 +- doc/std_time_timer.html | 12 +- doc/std_time_timestamp-source.html | 201 +- doc/std_time_timestamp.html | 54 +- doc/std_time_utc-source.html | 882 ++++- doc/std_time_utc.html | 68 +- 104 files changed, 23294 insertions(+), 1892 deletions(-) diff --git a/doc/book.html b/doc/book.html index 6f205ed76..af375689b 100644 --- a/doc/book.html +++ b/doc/book.html @@ -1,30 +1,5652 @@ - - + - - + + + + + The Koka Programming Language + + + + + + + + + + + +
+
+ +
+
+
The Koka Programming Language
+
(Daan Leijen, 2024-02-14)
+
+ +
+ +

koka-logo +

+
+
+ +
+ + + + + +

1. Getting started

+

Welcome to Koka – a strongly typed functional-style language with effect types and handlers. +

+

Why Koka? +A Tour of Koka +Install +Discussion forum +Github +Libraries

+
+

Note: Koka v3 is a research language that is currently under development +and not ready for production use. +Nevertheless, the language is stable and the compiler +implements the full specification. The main things lacking at the moment are +(async) libraries and package management. +

+
+

News: +

+
    +
  • +

    2024-02-14: Koka v3.1.0 released with a concurrent build system +and improved language service over the stdio protocol. Redesign of named effect +typing to match the formal system more closely. See samples/handlers/named for examples. +

  • +
  • +

    2024-01-25: Koka v3.0.4 released with improved VS Code hover and inlay information. +Splits std/core in multiple modules, fixes bug in infinite expansion for implicits +and various other small improvements. +

  • +
  • +

    2024-01-13: Koka v3.0.1 released with improved VS Code integration and inlay hints. Initial support for +locally qualified names and implicit parameters (see the samples/syntax). Various small bug fixes. +

  • +
  • +

    2023-12-30: Koka v2.6.0 released with VS Code language integration with type information, jump to definition, +run test functions directly from the editor, automatic Koka installation, and many more things. +Special thanks to Tim Whiting and Fredrik Wieczerkowski for all their work on making this possible! +

  • +
  • +

    2023-12-27: Update of the technical report on "The functional essence of binary trees" where we use fully-in-place programming and +the new hole contexts to create fully verified functional implementations of binary search tree +algorithms with performance on par with imperative C implementations. +

  • +
  • +

    2023-07-03: Koka v2.4.2 released: add support for fip and fbip keywords described +in “FP2: Fully in-Place Functional Programming” +(ICFP'23) [pdf]. +Various fixes and performance improvements. +

  • +
  • +

    2021-02-04 (pinned) The Context Free +youtube channel posted a short and fun video +about effects in Koka (and 12 (!) other languages). +

  • +
  • +

    2021-09-01 (pinned) The ICFP'21 tutorial +“Programming with Effect Handlers and FBIP in Koka” is now available on +youtube. +

  • +
  • +

    2022-02-07: Koka v2.4.0 released: improved specialization and int operations, add rbtree-fbip sample, +improve grammar (pub (instead of public, remove private (as everything is private by default now)), +final ctl (instead of brk), underscores in number literals, etc), rename double to float64, various bug fixes. +

  • +
  • +

    2021-12-27: Koka v2.3.8 released: improved int performance, various bug fixes, update wasm backend, +initial conan support, fix js backend. +

  • +
  • +

    2021-11-26: Koka v2.3.6 released: +maybe-like types are already value types, but now also no longer need heap allocation +if not nested (and [Just(1)] uses the same heap space as [1]), +improved atomic refcounting (by Anton Lorenzen), improved specialization (by Steven Fontanella), +various small fixes, add std/os/readline, fix build on freeBSD +

  • +
  • +

    2021-10-15: Koka v2.3.2 released, with initial wasm support +(use --target=wasm, and install emscripten and wasmtime), +improved reuse specialization (by Anton Lorenzen), and various bug fixes. +

  • +
  • +

    2021-09-29: Koka v2.3.1 released, with improved TRMC optimizations, and improved reuse +(the rbtree benchmark is as fast as C++ now), and +faster effect operations. Experimental: allow elision of -> in anonymous +function expressions (e.g. xs.map( fn(x) x + 1 )) and operation clauses. +Command line options changed a bit with .koka as the standard output directory. +

  • +
  • +

    2021-09-20: Koka v2.3.0 released, with new +brace elision and if/match +conditions without parenthesis. Updated the javascript backend +using ES6 modules and BigInt. new module std/num/int64, improved effect operation performance. +

  • +
  • +

    2021-09-05: Koka v2.2.1 released, with initial parallel tasks, the binary-trees benchmark, and +brace elision. +

  • +
  • +

    2021-08-26: Koka v2.2.0 released, improved simplification (by Rashika B), cross-module specialization (Steven Fontanella), +and borrowing annotations with improved reuse analysis (Anton Lorenzen). +

  • +
  • +

    2021-08-26: At 12:30 EST was the live Koka tutorial at +ICFP'21, +see it on youtube. +

  • +
  • +

    2021-08-23: “Generalized Evidence Passing for Effect Handlers”, by Ningning Xie and Daan Leijen presented at ICFP'21. +See it on youtube +or read the paper. +

  • +
  • +

    2021-08-22: “First-class Named Effect Handlers”, by Youyou Cong, Ningning Xie, and Daan Leijen presented at HOPE'21. +See it on youtube +or read the paper. +

  • +
  • +

    2021-06-23: Koka v2.1.9 released, initial cross-module specialization (by Steven Fontanella). +

  • +
  • +

    2021-06-17: Koka v2.1.8 released, initial Apple M1 support. +

  • +
  • +

    The Perceus paper won a distinguished paper award at PLDI'21! +

  • +
  • +

    2021-06-10: Koka v2.1.6 released. +

  • +
  • +

    2021-05-31: Koka v2.1.4 released. +

  • +
  • +

    2021-05-01: Koka v2.1.2 released. +

  • +
  • +

    2021-03-08: Koka v2.1.1 released. +

  • +
  • +

    2021-02-14: Koka v2.0.16 released. +

  • +
  • +

    2020-12-12: Koka v2.0.14 released. +

  • +
  • +

    2020-12-02: Koka v2.0.12 released. +

  • +
  • +

    2020-11-29: Perceus technical report publised (pdf). +

1.1. Installing the compiler

+ + +

1.1.1. Install with the VS Code editor

+

vscode-install +

+

The easiest way to start with Koka is to use the excellent VS Code editor +and install the Koka extension. +Go to the extension panel, search for Koka and +install the official extension as shown on the right. +

+

Installing the extension also prompts to install +the latest Koka compiler on your platform +(available for Windows x64, MacOS x64 and arm64, and Linux x64). +

+ + + +

Once installed, the samples directory is opened. You can also open this +manually from the command panel (Ctrl/Cmd+Shift+P), +and running the Koka: Open samples command (when you start typing the command will surface to the top). +Open for example the basic/caesar.kk file: +When you click run debug (or optimized) Koka compiles and runs the function, +showing the output in the VS Code terminal. +

+

vscode-caesar +

+

Press and hold ctrl+alt (or ctrl+option on MacOS) to show inlay hints – showing inferred +types, fully qualified names, and implicit arguments. +

+
+

vscode-inlay-off +

+

 versus  +

+

vscode-inlay-on

1.1.2. Manual Installation

+

On Windows (x64), open a cmd prompt and use: +

+

+
curl -sSL -o %tmp%\install-koka.bat https://github.com/koka-lang/koka/releases/latest/download/install.bat && %tmp%\install-koka.bat
+

On Linux (x64) and macOS (x64, arm64 (M1/M2)), you can install Koka using: +

+

+
curl -sSL https://github.com/koka-lang/koka/releases/latest/download/install.sh | sh
+

(If you previously installed Koka on macOS using brew, do an brew uninstall koka first). +On other platforms it is usually easy to build Koka from source instead. +

+ + + +

After installation, verify if Koka installed correctly: +

+
$ koka
+ _         _
+| |       | |
+| | _ ___ | | _ __ _
+| |/ / _ \| |/ / _' |  welcome to the koka interactive compiler
+|   ( (_) |   ( (_| |  version 2.4.0, Feb  7 2022, libc x64 (gcc)
+|_|\_\___/|_|\_\__,_|  type :? for help, and :q to quit
+
+loading: std/core
+loading: std/core/types
+loading: std/core/hnd
+>
+

Type :q to exit the interactive environment. +

+

For detailed installation instructions and other platforms see the releases page. +It is also straightforward to build the compiler from source. +

1.2. Running the compiler

+

vscode-codelens +

+

Note that when using the VS Code editor, you can directly compile and run public +functions that are named main, example..., or test... from +the editor environment. +

+

Of course, we can also run the compiler directly from a command line or +use the interactive environment. +

1.2.1. Command line usage

+

You can compile a Koka source as (note that all samples are pre-installed): +

+
$ koka samples/basic/caesar.kk
+compile: samples/basic/caesar.kk
+loading: std/core
+loading: std/core/types
+...
+check  : samples/basic/caesar
+linking: samples_basic_caesar
+created: .koka/v2.3.1/gcc-debug/samples_basic_caesar
+

and run the resulting executable: +

+
$ .koka/v2.3.1/gcc-debug/samples_basic_caesar
+plain  : Koka is a well-typed language
+encoded: Krnd lv d zhoo-wbshg odqjxdjh
+cracked: Koka is a well-typed language
+

The -O2 flag builds an optimized program. Let's try it on a purely functional implementation +of balanced insertion in a red-black tree (rbtree.kk): +

+
$ koka -O2 -o kk-rbtree samples/basic/rbtree.kk
+...
+linking: samples_basic_rbtree
+created: .koka/v2.3.1/gcc-drelease/samples_basic_rbtree
+created: kk-rbtree
+
+$ time ./kk-rbtree
+420000
+real    0m0.626s
+

(On Windows you can give the --kktime option to see the elapsed time). +We can compare this against an in-place updating C++ implementation using stl::map +(rbtree.cpp) (which also uses a +red-black tree internally): +

+
$ clang++ --std=c++17 -o cpp-rbtree -O3 /usr/local/share/koka/v2.3.1/lib/samples/basic/rbtree.cpp
+$ time ./cpp-rbtree
+420000
+real    0m0.667s
+

The excellent performance relative to C++ here (on Ubuntu 20.04 with an AMD 5950X) +is the result of Perceus automatically +transforming the fast path of the pure functional rebalancing to use mostly in-place updates, +closely mimicking the imperative rebalancing code of the hand optimized C++ library. +

1.2.2. Running the interactive compiler

+

Without giving any input files, the interactive environment runs by default: +

+
$ koka
+ _         _
+| |       | |
+| | _ ___ | | _ __ _
+| |/ / _ \| |/ / _' |  welcome to the koka interactive compiler
+|   ( (_) |   ( (_| |  version 2.3.1, Sep 21 2021, libc x64 (clang-cl)
+|_|\_\___/|_|\_\__,_|  type :? for help, and :q to quit
+
+loading: std/core
+loading: std/core/types
+loading: std/core/hnd
+>
+

Now you can test some expressions: +

+
> println("hi koka")
+check  : interactive
+check  : interactive
+linking: interactive
+created: .koka\v2.3.1\clang-cl-debug\interactive
+
+hi koka
+
+> :t "hi"
+string
+
+> :t println("hi")
+console ()
+

Or load a demo (use tab completion to avoid typing too much): +

+
> :l samples/basic/fibonacci
+> main()
+...
+
+The 10000th fibonacci number is 33644764876431783266621612005107543310302148460680063906564769974680081442166662368155595513633734025582065332680836159373734790483865268263040892463056431887354544369559827491606602099884183933864652731300088830269235673613135117579297437854413752130520504347701602264758318906527890855154366159582987279682987510631200575428783453215515103870818298969791613127856265033195487140214287532698187962046936097879900350962302291026368131493195275630227837628441540360584402572114334961180023091208287046088923962328835461505776583271252546093591128203925285393434620904245248929403901706233888991085841065183173360437470737908552631764325733993712871937587746897479926305837065742830161637408969178426378624212835258112820516370298089332099905707920064367426202389783111470054074998459250360633560933883831923386783056136435351892133279732908133732642652633989763922723407882928177953580570993691049175470808931841056146322338217465637321248226383092103297701648054726243842374862411453093812206564914032751086643394517512161526545361333111314042436854805106765843493523836959653428071768775328348234345557366719731392746273629108210679280784718035329131176778924659089938635459327894523777674406192240337638674004021330343297496902028328145933418826817683893072003634795623117103101291953169794607632737589253530772552375943788434504067715555779056450443016640119462580972216729758615026968443146952034614932291105970676243268515992834709891284706740862008587135016260312071903172086094081298321581077282076353186624611278245537208532365305775956430072517744315051539600905168603220349163222640885248852433158051534849622434848299380905070483482449327453732624567755879089187190803662058009594743150052402532709746995318770724376825907419939632265984147498193609285223945039707165443156421328157688908058783183404917434556270520223564846495196112460268313970975069382648706613264507665074611512677522748621598642530711298441182622661057163515069260029861704945425047491378115154139941550671256271197133252763631939606902895650288268608362241082050562430701794976171121233066073310059947366875
+

You can also set command line options in the interactive environment using :set <options>. +For example, we can load the rbtree example again and print out the elapsed runtime with --showtime: +

+
> :set --showtime
+> :l samples/basic/rbtree.kk
+> main()
+...
+
+420000
+info: elapsed: 4.104s, user: 4.046s, sys: 0.062s, rss: 231mb
+

and then enable optimizations with -O2 and run again (on Windows with an AMD 5950X): +

+
> :set -O2
+> :r
+> main()
+...
+
+420000
+info: elapsed: 0.670s, user: 0.656s, sys: 0.015s, rss: 198mb
+

And finally we quit the interpreter: +

+
> :q
+
+I think of my body as a side effect of my mind.
+  -- Carrie Fisher (1956)
+ + + +

What next? +

+

Basic Koka syntax +Browse the Library documentation +

2. Why Koka?

+

There are many new languages being designed, but only few +bring fundamentally new concepts – like Haskell with +pure versus monadic programming, or Rust with borrow checking. +Koka distinguishes itself through effect typing, effect handlers, +and Perceus memory management: +

+
+ + + + + + + + + +

2.1. Minimal but General

+

Koka has a small core set of +orthogonal, well-studied language features – but each of these is +as general and composable as possible, such that we do not need further +“special” extensions. Core features include first-class functions, +a higher-rank impredicative polymorphic type- and effect system, +algebraic data types, and effect handlers. +

fun hello-ten()
+  var i := 0
+  while { i < 10 }
+    println("hello")
+    i := i + 1
+fun hello-ten()
+  var i := 0
+  while { i < 10 }
+    println("hello")
+    i := i + 1
+
+ + + +

As an example of the min-gen design principle, Koka implements most +control-flow primitives as regular functions. An anonymous function can +be written as fn(){ <body> }; but as a syntactic convenience, any +function without arguments can be shortened further to use just braces, +as { <body> }. Moreover, using brace elision, any +indented block automatically gets curly braces. +

+

We can write a whilestd/core/while: forall<e> (predicate : () -> <div|e> bool, action : () -> <div|e> ()) -> <div|e> () loop now using regular +function calls as shown in the example, +where the call to whilestd/core/while: forall<e> (predicate : () -> <div|e> bool, action : () -> <div|e> ()) -> <div|e> () is desugared to +whilestd/core/while: forall<e> (predicate : () -> <div|e> bool, action : () -> <div|e> ()) -> <div|e> ()( fn(){ i < 10 }, fn(){ ... } ). +

+

This also naturally leads to +consistency: an expression between parenthesis is always evaluated +before a function call, whereas an expression between braces (ah, +suspenders!) is suspended and may be never evaluated or more than once +(as in our example). This is inconsistent in most other languages where +often the predicate of a whilestd/core/while: forall<e> (predicate : () -> <div|e> bool, action : () -> <div|e> ()) -> <div|e> () loop is written in parenthesis but may +be evaluated multiple times. +

+

Learn more about basic syntax

2.2. Effect Typing

+

Koka infers and tracks the effect of every function in its type – +and a function type has 3 parts: the argument types, the effect type, +and the type of the result. For example: +

fun sqr    : (int) -> total int       // total: mathematical total function    
+fun divide : (int,int) -> exn int     // exn: may raise an exception (partial)  
+fun turing : (tape) -> div int        // div: may not terminate (diverge)  
+fun print  : (string) -> console ()   // console: may write to the console  
+fun rand   : () -> ndet int           // ndet: non-deterministic  
+fun sqr    : (intstd/core/types/int: V) -> totalstd/core/types/total: E intstd/core/types/int: V       // total: mathematical total function    
+fun divide : (intstd/core/types/int: V,intstd/core/types/int: V) -> exnstd/core/exn/exn: (E, V) -> V intstd/core/types/int: V     // exn: may raise an exception (partial)  
+fun turing : (tape) -> divstd/core/types/div: X intstd/core/types/int: V        // div: may not terminate (diverge)  
+fun print  : (stringstd/core/types/string: V) -> consolestd/core/console/console: X ()   // console: may write to the console  
+fun rand   : () -> ndetstd/core/types/ndet: X intstd/core/types/int: V           // ndet: non-deterministic  
+
+ + + +

The precise effect typing gives Koka rock-solid semantics and deep +safety guarantees backed +by well-studied category theory, which makes Koka particularly easy to +reason about for both humans and compilers. (Given the importance of +effect typing, the name Koka was derived from the Japanese word for +effective +(効果, こうか, Kōka)). +

+

A function without any effect is called totalstd/core/types/total: E and corresponds to +mathematically total functions – a good place to be. Then we have +effects for partial functions that can raise exceptions (exnstd/core/exn/exn: (E, V) -> V), and +potentially non-terminating functions as divstd/core/types/div: X (divergent). The +combination of exnstd/core/exn/exn: (E, V) -> V and divstd/core/types/div: X is called purestd/core/pure: E as that corresponds to +Haskell's notion of purity. On top of that we find mutability (as ststd/core/types/st: H -> E) +up to full non-deterministic side effects in iostd/core/io: E. +

+

Effects can be polymorphic as well. Consider mapping a function over +a list: +

fun map( xs : list<a>, f : a -> e b ) : e list<b> 
+  match xs
+    Cons(x,xx) -> Cons( f(x), map(xx,f) )
+    Nil        -> Nil  
+fun map( xs : liststd/core/types/list: V -> V<a>, f : a -> e b ) : e liststd/core/types/list: V -> V<b> 
+  match xs
+    Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(x,xx) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>( f(x), map(xx,f) )
+    Nilstd/core/types/Nil: forall<a> list<a>        -> Nilstd/core/types/Nil: forall<a> list<a>  
+
+ + +

Single letter types are polymorphic (aka, generic), and Koka infers +that you map from a list of elements a to a list of elements of +type b. Since map itself has no intrinsic effect, the effect +of applying map is exactly the effect of the function f that +is applied, namely e. +

+

Learn more about effect types

2.3. Effect Handlers

+

Another example of the min-gen design principle: instead of +various special language and compiler extensions to support exceptions, +generators, async/await etc., Koka has full support for +algebraic effect handlers – these lets you define advanced control +abstractions like async/await as a user library in a typed and +composable way. +

+

Here is an example of an effect definition with +one control (ctl) operation to yield intstd/core/types/int: V values: +

effect yield
+  ctl yield( i : int ) : bool
+effectwhy/yield: (E, V) -> V yieldwhy/yield: (E, V) -> V
+  ctl yield( ii: int : intstd/core/types/int: V ) : boolstd/core/types/bool: V
+
+ + +

Once the effect is declared, we can use it +for example to yield the elements of a list: +

fun traverse( xs : list<int> ) : yield () 
+  match xs 
+    Cons(x,xx) -> if yield(x) then traverse(xx) else ()
+    Nil        -> ()
+fun traversewhy/traverse: (xs : list<int>) -> yield ()( xsxs: list<int> : liststd/core/types/list: V -> V<intstd/core/types/int: V> )result: -> yield () : yieldwhy/yield: (E, V) -> V (std/core/types/unit: V)std/core/types/unit: V 
+  match xsxs: list<int> 
+    Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: int,xxxx: list<int>) -> if yieldwhy/yield: (i : int) -> yield bool(xx: int) then traversewhy/traverse: (xs : list<int>) -> yield ()(xxxx: list<int>) else (std/core/types/Unit: ())std/core/types/Unit: ()
+    Nilstd/core/types/Nil: forall<a> list<a>        -> (std/core/types/Unit: ())std/core/types/Unit: ()
+
+ + +

The traversewhy/traverse: (xs : list<int>) -> yield () function calls yieldwhy/yield: (i : int) -> yield bool and therefore gets the yieldwhy/yield: (E, V) -> V effect in its type, +and if we want to use traversewhy/traverse: (xs : list<int>) -> yield (), we need to handle the yieldwhy/yield: (E, V) -> V effect. +This is much like defining an exception handler, except we can receive values (here an intstd/core/types/int: V), +and we can resume to the call-site with a result (here, with a boolean that determines if we keep traversing): +

fun print-elems() : console () 
+  with ctl yield(i)
+    println("yielded " ++ i.show)
+    resume(i<=2)
+  traverse([1,2,3,4])
+fun print-elemswhy/print-elems: () -> console ()()result: -> console () : consolestd/core/console/console: X (std/core/types/unit: V)std/core/types/unit: V 
+  withhandler: (() -> <yield,console> ()) -> console () ctl yieldyield: (i : int, resume : (bool) -> console ()) -> console ()
(ii: int) + printlnstd/core/console/string/println: (s : string) -> console ()("yielded "literal: string
count= 8
++std/core/types/(++): (x : string, y : string) -> console string ii: int.showstd/core/int/show: (i : int) -> console string) + resumeresume: (bool) -> console ()(ii: int<=std/core/int/(<=): (x : int, y : int) -> console bool2literal: int
dec = 2
hex8 = 0x02
bit8 = 0b00000010
) + traversewhy/traverse: (xs : list<int>) -> <yield,console> ()([std/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
,2literal: int
dec = 2
hex8 = 0x02
bit8 = 0b00000010
,3literal: int
dec = 3
hex8 = 0x03
bit8 = 0b00000011
,4literal: int
dec = 4
hex8 = 0x04
bit8 = 0b00000100
]std/core/types/Nil: forall<a> list<a>
) +
+ + +

The with statement dynamically binds the handler for yieldwhy/yield: (i : int) -> yield bool control operation over the +rest of the scope, in this case traversewhy/traverse: (xs : list<int>) -> yield ()([1,2,3,4]). +Every time yieldwhy/yield: (i : int) -> yield bool is called, our control handler is called, prints the current value, +and resumes to the call-site with a boolean result. +The dynamic binding here is quite safe since we still use static typing! Indeed, +the handler discharges the yieldwhy/yield: (E, V) -> V effect – and replaces +it with a consolestd/core/console/console: X effect (due to println). When we run the example, we get: +

+
yielded: 1
+yielded: 2
+yielded: 3
+

Learn more about with statements

+

Learn more about effect handlers

2.4. Perceus Optimized Reference Counting

+

perceus3 +

+

Perceus is the compiler optimized reference counting technique that Koka +uses for automatic memory management [13, 22]. This (together +with evidence passing [2325]) +enables Koka to compile directly to plain C code without needing a +garbage collector or runtime system. +

+

Perceus uses extensive static analysis to aggressively optimize the +reference counts. Here the strong semantic foundation of Koka helps a +lot: inductive data types cannot form cycles, and potential sharing +across threads can be reliably determined. +

+

Normally we need to make a fundamental choice when managing memory: +

+
    +
  • We either use manual memory management (C, C++, Rust) and we get +the best performance but at a significant programming burden, +
  • +
  • Or, we use garbage collection (OCaml, C#, Java, Go, etc.) but +but now we need a runtime system and pay a price in performance, +memory usage, and unpredictable latencies. +
+ +

perceus-perf +

+

With Perceus, we hope to cross this gap and our goal is to +be within 2x of the performance of C/C++. Initial benchmarks are +encouraging and show Koka to be close to C performance on various +memory intensive benchmarks. +

+

See benchmarks

+

Read the Perceus technical report

2.5. Reuse Analysis

+

Perceus also performs reuse analysis as part of reference +counting analysis. This pairs pattern matches with constructors of the +same size and reuses them in-place if possible. Take for example, +the map function over lists: +

fun map( xs : list<a>, f : a -> e b ) : e list<b>
+  match xs
+    Cons(x,xx) -> Cons( f(x), map(xx,f) )
+    Nil        -> Nil
+fun map( xs : liststd/core/types/list: V -> V<a>, f : a -> e b ) : e liststd/core/types/list: V -> V<b>
+  match xs
+    Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(x,xx) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>( f(x), map(xx,f) )
+    Nilstd/core/types/Nil: forall<a> list<a>        -> Nilstd/core/types/Nil: forall<a> list<a>
+
+ + + +

Here the matched Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a> can be reused by the new Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a> +in the branch. This means if we map over a list that is not shared, +like list(1,100000).map(sqr).sumstd/core/list/sum: (xs : list<int>) -> int, +then the list is updated in-place without any extra allocation. +This is very effective for many functional style programs. +

+ + +
void map( list_t xs, function_t f, 
+          list_t* res) 
+{
+  while (is_Cons(xs)) {
+    if (is_unique(xs)) {    // if xs is not shared..
+      box_t y = apply(dup(f),xs->head);      
+      if (yielding()) { ... } // if f yields to a general ctl operation..
+      else {
+        xs->head = y;      
+        *res = xs;          // update previous node in-place
+        res = &xs->tail;    // set the result address for the next node
+        xs = xs->tail;      // .. and continue with the next node
+      }
+    }
+    else { ... }            // slow path allocates fresh nodes
+  }
+  *res = Nil;  
+}
+

Moreover, the Koka compiler also implements tail-recursion modulo cons (TRMC) [11, 12] +and instead of using a recursive call, the function is eventually optimized +into an in-place updating loop for the fast path, similar to +the C code example on the right. +

+

Importantly, the reuse optimization is guaranteed +and a programmer can see when the optimization applies. +This leads to a new programming technique we call FBIP: +functional but in-place. Just like tail-recursion allows us +to express loops with regular function calls, reuse analysis +allows us to express many imperative algorithms in a purely +functional style. +

+

Learn more about FBIP

+

Read the paper on fully in-place functional programming

+

Read the paper on generalized tail-recursion modulo cons

2.6. Specialization

+

As another example of the effectiveness of Perceus and the strong semantics +of the Koka core language, we can +look at the red-black tree example and look at the code generated +when folding a binary tree. The red-black tree is defined as: +

type color  
+  Red
+  Black
+
+type tree<k,a> 
+  Leaf
+  Node(color : color, left : tree<k,a>, key : k, value : a, right : tree<k,a>)
+type colorwhy/color: V  
+  Redwhy/Red: color
+  Blackwhy/Black: color
+
+type treewhy/tree: (V, V) -> V<kk: V,aa: V> 
+  Leafwhy/Leaf: forall<a,b> tree<a,b>
+  Nodewhy/Node: forall<a,b> (color : color, left : tree<a,b>, key : a, value : b, right : tree<a,b>) -> tree<a,b>(color : colorwhy/color: V, left : treewhy/tree: (V, V) -> V<kk: V,aa: V>, key : kk: V, value : aa: V, right : treewhy/tree: (V, V) -> V<kk: V,aa: V>)
+
+ + + +

We can generically fold over a tree t with a function f as: +

fun fold(t : tree<k,a>, acc : b, f : (k, a, b) -> b) : b
+  match t
+    Node(_,l,k,v,r) -> r.fold( f(k,v,l.fold(acc,f)), f)
+    Leaf            -> acc
+fun foldwhy/fold: forall<a,b,c> (t : tree<c,a>, acc : b, f : (c, a, b) -> b) -> b(tt: tree<$251,$249> : treewhy/tree: (V, V) -> V<kk: V,aa: V>, accacc: $250 : bb: V, ff: ($251, $249, $250) -> $250 : (kk: V, aa: V, bb: V) -> bstd/core/types/total: E)result: -> total 335 : bstd/core/types/total: E
+  match tt: tree<$251,$249>
+    Nodewhy/Node: forall<a,b> (color : color, left : tree<a,b>, key : a, value : b, right : tree<a,b>) -> tree<a,b>(_,ll: tree<$251,$249>,kk: $251,vv: $249,rr: tree<$251,$249>) -> rr: tree<$251,$249>.foldwhy/fold: (t : tree<$251,$249>, acc : $250, f : ($251, $249, $250) -> $250) -> $250( ff: ($251, $249, $250) -> $250(kk: $251,vv: $249,ll: tree<$251,$249>.foldwhy/fold: (t : tree<$251,$249>, acc : $250, f : ($251, $249, $250) -> $250) -> $250(accacc: $250,ff: ($251, $249, $250) -> $250)), ff: ($251, $249, $250) -> $250)
+    Leafwhy/Leaf: forall<a,b> tree<a,b>            -> accacc: $250
+
+ + + +

This is used in the example to count all the Truestd/core/types/True: bool values in +a tree t : treewhy/tree: (V, V) -> V<k,boolstd/core/types/bool: V> as: +

val count = t.fold(0, fn(k,v,acc) if v then acc+1 else acc)
+val count = t.fold(0, fn(k,v,acc) if v then acc+1 else acc)
+
+ + + +

This may look quite expensive where we pass a polymorphic +first-class function that uses arbitrary precision integer arithmetic. +However, the Koka compiler first specializes the fold definition +to the passed function, then simplifies the resulting monomorphic code, +and finally applies Perceus to insert reference count instructions. +This results in the following internal core code: +

fun spec-fold(t : tree<k,bool>, acc : int) : int
+  match t
+    Node(_,l,k,v,r) -> 
+      if unique(t) then { drop(k); free(t) } else { dup(l); dup(r) } // perceus inserted
+      val x = if v then 1 else 0
+      spec-fold(r, spec-fold(l,acc) + x) 
+    Leaf -> 
+      drop(t)
+      acc
+
+val count = spec-fold(t,0)
+fun spec-fold(t : treewhy/tree: (V, V) -> V<k,boolstd/core/types/bool: V>, acc : intstd/core/types/int: V) : intstd/core/types/int: V
+  match t
+    Nodewhy/Node: forall<a,b> (color : color, left : tree<a,b>, key : a, value : b, right : tree<a,b>) -> tree<a,b>(_,l,k,v,r) -> 
+      if uniquestd/core/unique: () -> ndet int(t) then { drop(k); free(t) } else { dup(l); dup(r) } // perceus inserted
+      val x = if v then 1 else 0
+      spec-fold(r, spec-fold(l,acc) + x) 
+    Leafwhy/Leaf: forall<a,b> tree<a,b> -> 
+      drop(t)
+      acc
+
+val count = spec-fold(t,0)
+
+ + + +

When compiled via the C backend, the generated assembly instructions +on arm64 become: +

+
spec_fold:
+  ...                       
+  LOOP0:   
+    mov  x21, x0              ; x20 is t, x21 = acc (x19 = koka context _ctx)
+  LOOP1:                      ; the "match(t)" point
+    cmp  x20, #9              ; is t a Leaf?
+    b.eq LBB15_1              ;   if so, goto Leaf brach
+  LBB15_5:                    ;   otherwise, this is the Node(_,l,k,v,r) branch
+    mov  x23, x20             ; load the fields of t:
+    ldp  x22, x0, [x20, #8]   ;   x22 = l, x0 = k   (ldp == load pair)
+    ldp  x24, x20, [x20, #24] ;   x24 = v, x20 = r  
+    ldr  w8, [x23, #4]        ;   w8 = reference count (0 is unique)
+    cbnz w8, LBB15_11         ; if t is not unique, goto cold path to dup the members
+    tbz  w0, #0, LBB15_13     ; if k is allocated (bit 0 is 0), goto cold path to free it
+  LBB15_7:                   
+    mov  x0, x23              ; call free(t)  
+    bl   _mi_free
+  LBB15_8:              
+    mov  x0, x22              ; call spec_fold(l,acc,_ctx)
+    mov  x1, x21              
+    mov  x2, x19
+    bl   spec_fold
+    cmp  x24, #1              ; boxed value is False? 
+    b.eq LOOP0                ;   if v is False, the result in x0 is the accumulator
+    add  x21, x0, #4          ; otherwise add 1 (as a small int 4*n)
+    orr  x8, x21, #1          ;   check for bigint or overflow in one test 
+    cmp  x8, w21, sxtw        ;   (see kklib/include/integer.h for details)
+    b.eq LOOP1                ; and tail-call into spec_fold if no overflow or bigint
+    mov  w1, #5               ; otherwise, use generic bigint addition              
+    mov  x2, x19
+    bl   _kk_integer_add_generic
+    b    LOOP0   
+  ...
+

The polymorphic fold with its higher order parameter +is eventually compiled into a tight loop with close to optimal +assembly instructions. +

+
+

advancedHere we see too that the node t is freed explicitly as soon as it is +no longer live. This is usually earlier than scope-based deallocation +(like RAII) and therefore Perceus can guarantee to be garbage-free +where in a (cycle-free) program objects are always immediatedly +deallocated as soon as they become unreachable [1315, 22]. +Moreover, it is deterministic and behaves just like regular +malloc/free calls. +Reference counting may still seem expensive compared to trace-based garbage collection +which only (re)visits all live objects and never needs to free objects +explicitly. However, Perceus usually frees an object right after its +last use (like in our example), and thus the memory is still in the +cache reducing the cost of freeing it. Also, Perceus never (re)visits +live objects arbitrarily which may trash the caches especially if the +live set is large. As such, we think the deterministic behavior of +Perceus together with the garbage-free property may work out better +in practice.

+

Read the technical report on garbage-free and frame-limited reuse

+

Read the technical report on fully in-place functional programming

+

3. A Tour of Koka

+

This is a short introduction to the Koka programming language. +

+

Koka is a function-oriented language that separates pure values from +side-effecting computation (Given the importance of effect typing, +the name Koka was derived from the Japanese word for +effective +(効果, こうか, Kōka)). +

3.1. Basics

3.1.1. Hello world

+

As usual, we start with the familiar Hello world program: +

fun main()
+  println("Hello world!") // println output
+fun maintour/main: () -> console ()()result: -> console ()
+  printlnstd/core/console/string/println: (s : string) -> console ()("Hello world!"literal: string
count= 12
) // println output +
+ + +

Functions are declared using the fun keyword (and anonymous functions with fn). +Due to brace elision, any indented blocks implicitly get curly braces, +and the example can also be written as: +

fun main() {
+  println("Hello world!") // println output
+}
+fun maintour/main: () -> console ()() {
+  println("Hello world!") // println output
+}
+
+ + +

using explicit braces. Here is another short example program that encodes a string using the +Caesar cipher, where each lower-case letter in a string is replaced by the letter +three places up in the alphabet: +

fun main() { println(caesar("koka is fun")) }
+
+fun encode( s : string, shift : int )
+  fun encode-char(c)
+    if c < 'a' || c > 'z' then return c
+    val base = (c - 'a').int
+    val rot  = (base + shift) % 26
+    (rot.char + 'a')
+  s.map(encode-char)
+
+fun caesar( s : string ) : string
+  s.encode( 3 )
+fun encodetour/encode: (s : string, shift : int) -> string( ss: string : stringstd/core/types/string: V, shiftshift: int : intstd/core/types/int: V )result: -> total string
+  fun encode-charencode-char: (c : char) -> char(cc: char)result: -> total char
+    if cc: char <std/core/char/(<): (char, char) -> bool 'a'literal: char
unicode= u0061
||std/core/types/(||): (x : bool, y : bool) -> bool cc: char >std/core/char/(>): (char, char) -> bool 'z'literal: char
unicode= u007A
then returnreturn: char cc: char + val basebase: int = (cc: char -std/core/char/(-): (c : char, d : char) -> char 'a'literal: char
unicode= u0061
).intstd/core/char/int: (char) -> int + val rotrot: int = (basebase: int +std/core/int/(+): (x : int, y : int) -> int shiftshift: int) %std/core/int/(%): (int, int) -> int 26literal: int
dec = 26
hex8 = 0x1A
bit8 = 0b00011010
+ (rotrot: int.charstd/core/char/int/char: (i : int) -> char +std/core/char/(+): (c : char, d : char) -> char 'a'literal: char
unicode= u0061
) + ss: string.mapstd/core/list/string/map: (s : string, f : (char) -> char) -> string(encode-charencode-char: (c : char) -> char
) + +fun caesartour/caesar: (s : string) -> string( ss: string : stringstd/core/types/string: V )result: -> total string : stringstd/core/types/string: V + ss: string.encodetour/encode: (s : string, shift : int) -> string( 3literal: int
dec = 3
hex8 = 0x03
bit8 = 0b00000011
) +
+ + + +

In this example, we declare a local function encode-char which encodes a +single character c. The final statement s.map(encode-char) applies the +encode-char function to each character in the string s, returning a +new string where each character is Caesar encoded. The result of the final +statement in a function is also the return value of that function, and you can +generally leave out an explicit return keyword. +

3.1.2. Dot selection

+

Koka is a function-oriented language where functions and data form the +core of the language (in contrast to objects for example). In particular, the +expression s.encode(3) does not select the encode method from the +stringstd/core/types/string: V object, but it is simply syntactic sugar for the function call +encode(s,3) where s becomes the first argument. Similarly, c.int +converts a character to an integer by calling int(c) (and both expressions +are equivalent). The dot notation is intuïtive and quite convenient to +chain multiple calls together, as in: +

fun showit( s : string )
+  s.encode(3).count.println
+fun showittour/showit: (s : string) -> console ()( ss: string : stringstd/core/types/string: V )result: -> console ()
+  ss: string.encodetour/encode: (s : string, shift : int) -> console string(3literal: int
dec = 3
hex8 = 0x03
bit8 = 0b00000011
).countstd/core/string/count: (s : string) -> console int.printlnstd/core/console/show/println: (x : int, @implicit/show : (int) -> string) -> console ()
?show=int/show
+
+ + + +

for example (where the body desugars as println(count(encode(s,3)))). An +advantage of the dot notation as syntactic sugar for function calls is that it +is easy to extend the ‘primitive’ methods of any data type: just write a new +function that takes that type as its first argument. In most object-oriented +languages one would need to add that method to the class definition itself +which is not always possible if such class came as a library for example. +

3.1.3. Type Inference

+

Koka is also strongly typed. It uses a powerful type inference engine to +infer most types, and types generally do not get in the way. In +particular, you can always leave out the types of any local variables. +This is the case for example for base and rot values in the +previous example; hover with the mouse over the example to see the types +that were inferred by Koka. Generally, it is good practice though to +write type annotations for function parameters and the function result +since it both helps with type inference, and it provides useful +documentation with better feedback from the compiler. +

+

For the encode function it is actually essential to give the type of +the s parameter: since the map function is defined for both liststd/core/types/list: V -> V +and stringstd/core/types/string: V types and the program is ambiguous without an annotation. +Try to load the example in the editor and remove the annotation to see +what error Koka produces. +

3.1.4. Anonymous Functions and Trailing Lambdas

+

Koka also allows for anonymous function expressions using the fn keyword. +For example, instead of +declaring the encode-char function, we can also pass it directly to +the map function as a function expression: +

fun encode2( s : string, shift : int )
+  s.map( fn(c)
+    if c < 'a' || c > 'z' then return c
+    val base = (c - 'a').int
+    val rot  = (base + shift) % 26
+    (rot.char + 'a')
+  )
+fun encode2tour/encode2: (s : string, shift : int) -> string( ss: string : stringstd/core/types/string: V, shiftshift: int : intstd/core/types/int: V )result: -> total string
+  ss: string.mapstd/core/list/string/map: (s : string, f : (char) -> char) -> string( fnfn: (c : char) -> char(cc: char)
+    if cc: char <std/core/char/(<): (char, char) -> bool 'a'literal: char
unicode= u0061
||std/core/types/(||): (x : bool, y : bool) -> bool cc: char >std/core/char/(>): (char, char) -> bool 'z'literal: char
unicode= u007A
then returnreturn: char cc: char + val basebase: int = (cc: char -std/core/char/(-): (c : char, d : char) -> char 'a'literal: char
unicode= u0061
).intstd/core/char/int: (char) -> int + val rotrot: int = (basebase: int +std/core/int/(+): (x : int, y : int) -> int shiftshift: int) %std/core/int/(%): (int, int) -> int 26literal: int
dec = 26
hex8 = 0x1A
bit8 = 0b00011010
+ (rotrot: int.charstd/core/char/int/char: (i : int) -> char +std/core/char/(+): (c : char, d : char) -> char 'a'literal: char
unicode= u0061
) +
) +
+ + + +

It is a bit annoying we had to put the final right-parenthesis after the last +brace in the previous example. As a convenience, Koka allows anonymous functions to follow +the function call instead – this is also known as trailing lambdas. +For example, here is how we can print the numbers +1 to 10: +

fun main() { print10() }
+
+fun print10()
+  for(1,10) fn(i)
+    println(i)
+fun print10tour/print10: () -> console ()()result: -> console ()
+  forstd/core/range/for: (start : int, end : int, action : (int) -> console ()) -> console ()(1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
,10literal: int
dec = 10
hex8 = 0x0A
bit8 = 0b00001010
) fnfn: (i : int) -> console ()(ii: int) + printlnstd/core/console/show/println: (x : int, @implicit/show : (int) -> string) -> console ()
?show=int/show
(ii: int
) +
+ + + +

which is desugared to for( 1, 10, fn(i){ println(i) } ). (In fact, since we +pass the i argument directly to println, we could have also passed the function itself +directly as for(1,10,println).) +

+

Anonymous functions without any arguments can be shortened further by leaving +out the fn keyword as well and just use braces directly. Here is an example using +the repeat function: +

fun main() { printhi10() }
+
+fun printhi10()
+  repeat(10)
+    println("hi")
+fun printhi10tour/printhi10: () -> console ()()result: -> console ()
+  repeatstd/core/repeat: (n : int, action : () -> console ()) -> console ()(10literal: int
dec = 10
hex8 = 0x0A
bit8 = 0b00001010
) + printlnstd/core/console/string/println: (s : string) -> console ()("hi"literal: string
count= 2
) +
+ + + +

where the body desugars to repeat( 10, { println(hi) } ) which +desugars further to repeat( 10, fn(){ println(hi)} ). The is +especially convenient for the whilestd/core/while: forall<e> (predicate : () -> <div|e> bool, action : () -> <div|e> ()) -> <div|e> () loop since this is not a built-in +control flow construct but just a regular function: +

fun main() { print11() }
+
+fun print11()
+  var i := 10
+  while { i >= 0 }
+    println(i)
+    i := i - 1
+fun print11tour/print11: () -> <console,div> ()()result: -> <console,div> ()
+  var ii: local-var<$3085,int> := 10literal: int
dec = 10
hex8 = 0x0A
bit8 = 0b00001010
+ whilestd/core/while: (predicate : () -> <div,local<$3085>,console> bool, action : () -> <div,local<$3085>,console> ()) -> <div,local<$3085>,console> () { ii: int >=std/core/int/(>=): (x : int, y : int) -> <local<$3085>,div,console> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
} + printlnstd/core/console/show/println: (x : int, @implicit/show : (int) -> string) -> <console,local<$3085>,div> ()
?show=int/show
(ii: int) + ii: local-var<$3085,int> :=std/core/types/local-set: (v : local-var<$3085,int>, assigned : int) -> <local<$3085>,console,div> () ii: int -std/core/int/(-): (x : int, y : int) -> <local<$3085>,console,div> int
1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
+
+ + + +

Note how the first argument to whilestd/core/while: forall<e> (predicate : () -> <div|e> bool, action : () -> <div|e> ()) -> <div|e> () is in braces instead of the usual +parenthesis. In Koka, an expression between parenthesis is always evaluated +before a function call, whereas an expression between braces (ah, +suspenders!) is suspended and may be never evaluated or more than once +(as in our example). +

3.1.5. With Statements

+

To the best of our knowledge, Koka was the first language to have +generalized trailing lambdas. It was also one of the first languages +to have dot notation (This was independently developed but it turns out +the D language has a similar feature (called UFCS) which predates dot-notation). +Another novel syntactical feature is the with statement. +With the ease of passing a function block as a parameter, these +often become nested. For example: +

fun twice(f)
+  f()
+  f()
+
+fun test-twice()
+  twice
+    twice
+      println("hi")
+fun twicetour/twice: forall<a,e> (f : () -> e a) -> e a(ff: () -> _3542 _3543)result: -> total string
+  ff: () -> _3542 _3543()
+  ff: () -> _3542 _3543()
+
+fun test-twicetour/test-twice: () -> console ()()result: -> console ()
+  twicetour/twice: (f : () -> console ()) -> console ()
+    twicetour/twice: (f : () -> console ()) -> console ()
+      printlnstd/core/console/string/println: (s : string) -> console ()("hi"literal: string
count= 2
) +
+ + +

where "hi" is printed four times (note: this desugars +to twicetour/twice: forall<a,e> (f : () -> e a) -> e a( fn(){ twicetour/twice: forall<a,e> (f : () -> e a) -> e a( fn(){ println("hi") }) })). +Using the with statement +we can write this more concisely as: +

pub fun test-with1()
+  with twice
+  with twice
+  println("hi")
+pub fun test-with1tour/test-with1: () -> console ()()result: -> console ()
+  withwith: () -> console () twicetour/twice: (f : () -> console ()) -> console ()
+  withwith: () -> console () twicetour/twice: (f : () -> console ()) -> console ()
+  printlnstd/core/console/string/println: (s : string) -> console ()("hi"literal: string
count= 2
) +
+ + + +

The with statement essentially puts all statements that follow it into +an anynomous function block and passes that as the last parameter. In general: +

+
+

translation

+
with f(e1,...,eN)
+<body>
+with f(e1,...,eN)
+<body>
+
+ + +

$\mathpre{\rightsquigarrow}$ +

f(e1,...,eN, fn(){ <body> })
+f(e1,...,eN, fn(){ <body> })
+
+
+

Moreover, a with statement can also bind a variable parameter as: +

+
+

translation

+
with x <- f(e1,...,eN)
+<body>
+with x <- f(e1,...,eN)
+<body>
+
+ + +

$\mathpre{\rightsquigarrow}$ +

f(e1,...,eN, fn(x){ <body> })
+f(e1,...,eN, fn(x){ <body> })
+
+
+

Here is an example using foreach to span over the rest of the function body: +

pub fun test-with2() {
+  with x <- list(1,10).foreach
+  println(x)
+}
+pub fun test-with2tour/test-with2: () -> console ()()result: -> console () {
+  withwith: (x : int) -> console () xx: int <- liststd/core/list/list: (lo : int, hi : int) -> console list<int>(1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
,10literal: int
dec = 10
hex8 = 0x0A
bit8 = 0b00001010
).foreachstd/core/list/foreach: (xs : list<int>, action : (int) -> console ()) -> console () + printlnstd/core/console/show/println: (x : int, @implicit/show : (int) -> string) -> console ()
?show=int/show
(xx: int) +
} +
+ + + +

which desugars to list(1,10).foreach( fn(x){ println(x) } ). +This is a bit reminiscent of Haskell do notation. +Using the with statement this way may look a bit strange at first +but is very convenient in practice – it helps thinking of with as +a closure over the rest of the lexical scope. +

With Finally

+

As another example, the finallystd/core/hnd/finally: forall<a,e> (fin : () -> e (), action : () -> e a) -> e a function takes as its first argument a +function that is run when exiting the scope – either normally, +or through an “exception” (i.e. when an effect operation does not resume). +Again, with is a natural fit: +

fun test-finally()
+  with finally{ println("exiting..") }
+  println("entering..")
+  throw("oops") + 42
+fun test-finallytour/test-finally: () -> <console,exn> int()result: -> <console,exn> int
+  withwith: () -> <console,exn> int finallystd/core/hnd/finally: (fin : () -> <console,exn> (), action : () -> <console,exn> int) -> <console,exn> int{ printlnstd/core/console/string/println: (s : string) -> <console,exn> ()("exiting.."literal: string
count= 9
) } + printlnstd/core/console/string/println: (s : string) -> <console,exn> ()("entering.."literal: string
count= 10
) + throwstd/core/exn/throw: (message : string, info : ? exception-info) -> <exn,console> int("oops"literal: string
count= 4
) +std/core/int/(+): (x : int, y : int) -> <exn,console> int 42literal: int
dec = 42
hex8 = 0x2A
bit8 = 0b00101010
+
+ + +

which desugars to finallystd/core/hnd/finally: forall<a,e> (fin : () -> e (), action : () -> e a) -> e a(fn(){ println(...) }, fn(){ println("entering"); throwstd/core/exn/throw: forall<a> (message : string, info : ? exception-info) -> exn a("oops") + 42 }), +and prints: +

+
entering..
+exiting..
+uncaught exception: oops
+

This is another example of the min-gen principle: many languages have +have special built-in support for this kind of pattern, like a defer statement, but in Koka +it is all just function applications with minimal syntactic sugar. +

+

Read more about initially and finally handlers +

With Handlers

+

The with statement is especially useful in combination with +effect handlers. An effect describes an abstract set of operations +whose concrete implementation can be dynamically bound by a handler. +Here is an example of an effect handler for emitting messages: +

// declare an abstract operation: emit, how it emits is defined dynamically by a handler.
+effect fun emit(msg : string) : ()
+
+// emit a standard greeting.
+fun hello() : emit ()
+  emit("hello world!")
+
+// emit a standard greeting to the console.
+pub fun hello-console1() : console ()
+  with handler
+    fun emit(msg) println(msg)
+  hello()
+// declare an abstract operation: emit, how it emits is defined dynamically by a handler.
+effecttour/emit: (E, V) -> V fun emittour/emit: (E, V) -> V(msgmsg: string : stringstd/core/types/string: V) : (std/core/types/unit: V)std/core/types/unit: V
+
+// emit a standard greeting.
+fun hellotour/hello: () -> emit ()()result: -> emit () : emittour/emit: (E, V) -> V (std/core/types/unit: V)std/core/types/unit: V
+  emittour/emit: (msg : string) -> emit ()("hello world!"literal: string
count= 12
) + +// emit a standard greeting to the console. +pub fun hello-console1tour/hello-console1: () -> console ()()result: -> console () : consolestd/core/console/console: X (std/core/types/unit: V)std/core/types/unit: V + withwith: () -> <emit,console> () handlerhandler: (() -> <emit,console> ()) -> console () + fun emitemit: (msg : string) -> console ()(msgmsg: string) printlnstd/core/console/string/println: (s : string) -> console ()(msgmsg: string) + hellotour/hello: () -> <emit,console> ()() +
+ + +

In this example, the with expression desugars to (handler{ fun emittour/emit: (msg : string) -> emit ()(msg){ println(msg) } })( fn(){ hellotour/hello: () -> emit ()() } ). +Generally, a handler{ <ops> } expression takes +as its last argument a function block so it can be used directly with with. +

+

Moreover, as a convenience, we can leave out the handler keyword +for effects that define just one operation (like emittour/emit: (E, V) -> V): +

+
+

translation

+
with val op = <expr>
+with fun op(x){ <body> }
+with ctl op(x){ <body> }
+with val op = <expr>
+with fun op(x){ <body> }
+with ctl op(x){ <body> }
+
+ + +

$\mathpre{\rightsquigarrow}$ +

with handler{ val op = <expr> }
+with handler{ fun op(x){ <body> } }
+with handler{ ctl op(x){ <body> } }
+with handler{ val op = <expr> }
+with handler{ fun op(x){ <body> } }
+with handler{ ctl op(x){ <body> } }
+
+
+

Using this convenience, we can write the previous example in more concisely as: +

pub fun hello-console2()
+  with fun emit(msg) println(msg)
+  hello()
+pub fun hello-console2()
+  with fun emittour/emit: (msg : string) -> emit ()(msg) println(msg)
+  hellotour/hello: () -> emit ()()
+
+ + + +

Intuitively, we can view the handler with fun emittour/emit: (msg : string) -> emit () as a (statically typed) dynamic binding +of the function emittour/emit: (msg : string) -> emit () over the rest of the scope. +

+

Read more about effect handlers

+

Read more about val operations

3.1.6. Optional and Named Parameters

+

Being a function-oriented language, Koka has powerful support for function +calls where it supports both optional and named parameters. For example, the +function replace-allstd/core/string/replace-all: (s : string, pattern : string, repl : string) -> string takes a string, a pattern (named pattern), and +a replacement string (named repl): +

fun main() { println(world()) }
+
+fun world()
+  replace-all("hi there", "there", "world")  // returns "hi world"
+fun worldtour/world: () -> string()result: -> total string
+  replace-allstd/core/string/replace-all: (s : string, pattern : string, repl : string) -> string("hi there"literal: string
count= 8
, "there"literal: string
count= 5
, "world"literal: string
count= 5
) // returns "hi world" +
+ + + +

Using named parameters, we can also write the function call as: +

fun main() { println(world2()) }
+
+fun world2()
+  "hi there".replace-all( repl="world", pattern="there" )
+fun world2tour/world2: () -> string()result: -> total string
+  "hi there"literal: string
count= 8
.replace-allstd/core/string/replace-all: (s : string, pattern : string, repl : string) -> string( repl="world"literal: string
count= 5
, pattern="there"literal: string
count= 5
) +
+ + + +

Optional parameters let you specify default values for parameters that do not +need to be provided at a call-site. As an example, let's define a function +sublisttour/sublist: forall<a> (xs : list<a>, start : int, len : ? int) -> list<a> that takes a list, a start position, and the length len of the desired +sublist. We can make the len parameter optional and by default return all +elements following the start position by picking the length of the input list by +default: +

fun main() { println( ['a','b','c'].sublist(1).string ) }
+
+fun sublist( xs : list<a>, start : int, len : int = xs.length ) : list<a>
+  if start <= 0 return xs.take(len)
+  match xs
+    Nil        -> Nil
+    Cons(_,xx) -> xx.sublist(start - 1, len)
+fun sublisttour/sublist: forall<a> (xs : list<a>, start : int, len : ? int) -> list<a>( xsxs: list<$8542> : liststd/core/types/list: V -> V<aa: V>, startstart: int : intstd/core/types/int: V, lenlen: ? int : intstd/core/types/int: V = xsxs: list<$8542>.lengthstd/core/list/length: (xs : list<$8542>) -> int )result: -> total list<8619> : liststd/core/types/list: V -> V<aa: V>
+  if startstart: int <=std/core/int/(<=): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
returnreturn: list<$8542> xsxs: list<$8542>.takestd/core/list/take: (xs : list<$8542>, n : int) -> list<$8542>(lenlen: int)std/core/types/Unit: () + match xsxs: list<$8542> + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(_,xxxx: list<$8542>) -> xxxx: list<$8542>.sublisttour/sublist: (xs : list<$8542>, start : int, len : ? int) -> list<$8542>(startstart: int -std/core/int/(-): (x : int, y : int) -> int 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
, lenlen: int
) +
+ + + +

Hover over the sublisttour/sublist: forall<a> (xs : list<a>, start : int, len : ? int) -> list<a> identifier to see its full type, where the len +parameter has gotten an optional intstd/core/types/int: V type signified by the question mark: +? intstd/core/types/int: V. +

3.1.7. A larger example: cracking Caesar encoding

+

Here is a slightly larger program inspired by an +example in Graham Hutton's most +excellent "Programming in Haskell" book: +

fun main()
+  test-uncaesar()
+
+fun encode( s : string, shift : int )
+  fun encode-char(c)
+    if c < 'a' || c > 'z' return c
+    val base = (c - 'a').int
+    val rot  = (base + shift) % 26
+    (rot.char + 'a')
+  s.map(encode-char)
+
+// The letter frequency table for English
+val english = [8.2,1.5,2.8,4.3,12.7,2.2,
+               2.0,6.1,7.0,0.2,0.8,4.0,2.4,
+               6.7,7.5,1.9,0.1, 6.0,6.3,9.1,
+               2.8,1.0,2.4,0.2,2.0,0.1]
+
+// Small helper functions
+fun percent( n : int, m : int )
+  100.0 * (n.float64 / m.float64)
+
+fun rotate( xs : list<a>, n : int ) : list<a>
+  xs.drop(n) ++ xs.take(n)
+
+// Calculate a frequency table for a string
+fun freqs( s : string ) : list<float64>
+  val lowers = list('a','z')
+  val occurs = lowers.map( fn(c) s.count(c.string) )
+  val total  = occurs.sum
+  occurs.map( fn(i) percent(i,total) )
+
+// Calculate how well two frequency tables match according
+// to the _chi-square_ statistic.
+fun chisqr( xs : list<float64>, ys : list<float64> ) : float64
+  zipwith(xs,ys, fn(x,y) ((x - y)^2.0)/y ).foldr(0.0,(+))
+
+// Crack a Caesar encoded string
+fun uncaesar( s : string ) : string
+  val table  = freqs(s)                   // build a frequency table for `s`
+  val chitab = list(0,25).map fn(n)       // build a list of chisqr numbers for each shift between 0 and 25
+                 chisqr( table.rotate(n), english )
+
+  val min    = chitab.minimum()           // find the mininal element
+  val shift  = chitab.index-of( fn(f) f == min ).negate  // and use its position as our shift
+  s.encode( shift )
+
+fun test-uncaesar()
+  println( uncaesar( "nrnd lv d ixq odqjxdjh" ) )
+// The letter frequency table for English
+val englishtour/english: list<float64> = [std/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>8.2literal: float64
hex64= 0x1.0666666666666p3
,1.5literal: float64
hex64= 0x1.8p0
,2.8literal: float64
hex64= 0x1.6666666666666p1
,4.3literal: float64
hex64= 0x1.1333333333333p2
,12.7literal: float64
hex64= 0x1.9666666666666p3
,2.2literal: float64
hex64= 0x1.199999999999ap1
, + 2.0literal: float64
hex64= 0x1p1
,6.1literal: float64
hex64= 0x1.8666666666666p2
,7.0literal: float64
hex64= 0x1.cp2
,0.2literal: float64
hex64= 0x1.999999999999ap-3
,0.8literal: float64
hex64= 0x1.999999999999ap-1
,4.0literal: float64
hex64= 0x1p2
,2.4literal: float64
hex64= 0x1.3333333333333p1
, + 6.7literal: float64
hex64= 0x1.acccccccccccdp2
,7.5literal: float64
hex64= 0x1.ep2
,1.9literal: float64
hex64= 0x1.e666666666666p0
,0.1literal: float64
hex64= 0x1.999999999999ap-4
, 6.0literal: float64
hex64= 0x1.8p2
,6.3literal: float64
hex64= 0x1.9333333333333p2
,9.1literal: float64
hex64= 0x1.2333333333333p3
, + 2.8literal: float64
hex64= 0x1.6666666666666p1
,1.0literal: float64
hex64= 0x1p0
,2.4literal: float64
hex64= 0x1.3333333333333p1
,0.2literal: float64
hex64= 0x1.999999999999ap-3
,2.0literal: float64
hex64= 0x1p1
,0.1literal: float64
hex64= 0x1.999999999999ap-4
]std/core/types/Nil: forall<a> list<a> + +// Small helper functions +fun percenttour/percent: (n : int, m : int) -> float64( nn: int : intstd/core/types/int: V, mm: int : intstd/core/types/int: V )result: -> total float64 + 100.0literal: float64
hex64= 0x1.9p6
*std/num/float64/(*): (x : float64, y : float64) -> float64 (nn: int.float64std/num/float64/float64: (i : int) -> float64 /std/num/float64/(/): (x : float64, y : float64) -> float64 mm: int.float64std/num/float64/float64: (i : int) -> float64
) + +fun rotatetour/rotate: forall<a> (xs : list<a>, n : int) -> list<a>( xsxs: list<$3282> : liststd/core/types/list: V -> V<aa: V>, nn: int : intstd/core/types/int: V )result: -> total list<3312> : liststd/core/types/list: V -> V<aa: V> + xsxs: list<$3282>.dropstd/core/list/drop: (xs : list<$3282>, n : int) -> list<$3282>(nn: int) ++std/core/list/(++): (xs : list<$3282>, ys : list<$3282>) -> list<$3282> xsxs: list<$3282>.takestd/core/list/take: (xs : list<$3282>, n : int) -> list<$3282>(nn: int) + +// Calculate a frequency table for a string +fun freqstour/freqs: (s : string) -> list<float64>( ss: string : stringstd/core/types/string: V )result: -> total list<float64> : liststd/core/types/list: V -> V<float64std/core/types/float64: V> + val lowerslowers: list<char> = liststd/core/list/char/list: (lo : char, hi : char) -> list<char>('a'literal: char
unicode= u0061
,'z'literal: char
unicode= u007A
) + val occursoccurs: list<int> = lowerslowers: list<char>.mapstd/core/list/map: (xs : list<char>, f : (char) -> int) -> list<int>( fnfn: (c : char) -> int(cc: char) ss: string.countstd/core/string/stringpat/count: (s : string, pattern : string) -> int(cc: char.stringstd/core/string/char/string: (c : char) -> string) ) + val totaltotal: int = occursoccurs: list<int>.sumstd/core/list/sum: (xs : list<int>) -> int + occursoccurs: list<int>.mapstd/core/list/map: (xs : list<int>, f : (int) -> float64) -> list<float64>( fnfn: (i : int) -> float64(ii: int) percenttour/percent: (n : int, m : int) -> float64(ii: int,totaltotal: int)
) + +// Calculate how well two frequency tables match according +// to the _chi-square_ statistic. +fun chisqrtour/chisqr: (xs : list<float64>, ys : list<float64>) -> float64( xsxs: list<float64> : liststd/core/types/list: V -> V<float64std/core/types/float64: V>, ysys: list<float64> : liststd/core/types/list: V -> V<float64std/core/types/float64: V> )result: -> total float64 : float64std/core/types/float64: V + zipwithstd/core/list/zipwith: (xs : list<float64>, ys : list<float64>, f : (float64, float64) -> float64) -> list<float64>(xsxs: list<float64>,ysys: list<float64>, fnfn: (x : float64, y : float64) -> float64(xx: float64,yy: float64) ((xx: float64 -std/num/float64/(-): (x : float64, y : float64) -> float64 yy: float64)^std/num/float64/(^): (f : float64, p : float64) -> float642.0literal: float64
hex64= 0x1p1
)/std/num/float64/(/): (x : float64, y : float64) -> float64yy: float64 ).foldrstd/core/list/foldr: (xs : list<float64>, z : float64, f : (float64, float64) -> float64) -> float64(0.0literal: float64
hex64= 0x0p+0
,(+)std/num/float64/(+): (x : float64, y : float64) -> float64
) + +// Crack a Caesar encoded string +fun uncaesartour/uncaesar: (s : string) -> string( ss: string : stringstd/core/types/string: V )result: -> total string : stringstd/core/types/string: V + val tabletable: list<float64> = freqstour/freqs: (s : string) -> list<float64>(ss: string) // build a frequency table for `s` + val chitabchitab: list<float64> = liststd/core/list/list: (lo : int, hi : int) -> list<int>(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
,25literal: int
dec = 25
hex8 = 0x19
bit8 = 0b00011001
).mapstd/core/list/map: (xs : list<int>, f : (int) -> float64) -> list<float64> fnfn: (n : int) -> float64(nn: int) // build a list of chisqr numbers for each shift between 0 and 25 + chisqrtour/chisqr: (xs : list<float64>, ys : list<float64>) -> float64( tabletable: list<float64>.rotatetour/rotate: (xs : list<float64>, n : int) -> list<float64>(nn: int), englishtour/english: list<float64> ) + + val minmin: float64 = chitabchitab: list<float64>.minimumstd/num/float64/minimum: (xs : list<float64>) -> float64() // find the mininal element + val shiftshift: int = chitabchitab: list<float64>.index-ofstd/core/list/index-of: (xs : list<float64>, pred : (float64) -> bool) -> int( fnfn: (f : float64) -> bool(ff: float64) ff: float64 ==std/num/float64/(==): (x : float64, y : float64) -> bool minmin: float64 ).negatestd/core/int/negate: (i : int) -> int // and use its position as our shift + ss: string.encodetour/encode: (s : string, shift : int) -> string( shiftshift: int
) + +fun test-uncaesartour/test-uncaesar: () -> console ()()result: -> console () + printlnstd/core/console/string/println: (s : string) -> console ()( uncaesartour/uncaesar: (s : string) -> console string( "nrnd lv d ixq odqjxdjh"literal: string
count= 22
)
) +
+ + + +

The val keyword declares a static value. In the example, the value englishtour/english: list<float64> +is a list of floating point numbers (of type float64std/core/types/float64: V) denoting the average +frequency for each letter. The function freqstour/freqs: (s : string) -> list<float64> builds a frequency table for a +specific string, while the function chisqrtour/chisqr: (xs : list<float64>, ys : list<float64>) -> float64 calculates how well two frequency +tables match. In the function crack these functions are used to find a +shift value that results in a string whose frequency table matches the +englishtour/english: list<float64> one the closest – and we use that to decode the string. +You can try out this example directly in the interactive environment: +

+
> :l samples/basic/caesar.kk

3.2. Effect types

+

A novel part about Koka is that it automatically infers all the side effects +that occur in a function. The absence of any effect is denoted as totalstd/core/types/total: E (or +<>) and corresponds to pure mathematical functions. If a function can raise +an exception the effect is exnstd/core/exn/exn: (E, V) -> V, and if a function may not terminate the +effect is divstd/core/types/div: X (for divergence). The combination of exnstd/core/exn/exn: (E, V) -> V and divstd/core/types/div: X is +purestd/core/pure: E and corresponds directly to Haskell's notion of purity. Non- +deterministic functions get the ndetstd/core/types/ndet: X effect. The ‘worst’ effect is iostd/core/io: E +and means that a program can raise exceptions, not terminate, be non- +deterministic, read and write to the heap, and do any input/output operations. +Here are some examples of effectful functions: +

fun square1( x : int ) : total int   { x*x }
+fun square2( x : int ) : console int { println( "a not so secret side-effect" ); x*x }
+fun square3( x : int ) : div int     { x * square3( x ) }
+fun square4( x : int ) : exn int     { throw( "oops" ); x*x }
+fun square1tour/square1: (x : int) -> int( xx: int : intstd/core/types/int: V )result: -> total int : totalstd/core/types/total: E intstd/core/types/int: V   { xx: int*std/core/int/(*): (int, int) -> intxx: int }
+fun square2tour/square2: (x : int) -> console int( xx: int : intstd/core/types/int: V )result: -> console int : consolestd/core/console/console: X intstd/core/types/int: V { printlnstd/core/console/string/println: (s : string) -> console ()( "a not so secret side-effect"literal: string
count= 27
); xx: int*std/core/int/(*): (int, int) -> console intxx: int
} +fun square3tour/square3: (x : int) -> div int( xx: int : intstd/core/types/int: V )result: -> div int : divstd/core/types/div: X intstd/core/types/int: V { xx: int *std/core/int/(*): (int, int) -> div int square3tour/square3: (x : int) -> div int( xx: int ) } +fun square4tour/square4: (x : int) -> exn int( xx: int : intstd/core/types/int: V )result: -> exn int : exnstd/core/exn/exn: (E, V) -> V intstd/core/types/int: V { throwstd/core/exn/throw: (message : string, info : ? exception-info) -> exn _3373( "oops"literal: string
count= 4
); xx: int*std/core/int/(*): (int, int) -> exn intxx: int
} +
+ + + +

When the effect is totalstd/core/types/total: E we usually leave it out in the type annotation. +For example, when we write: +

fun square5( x : int ) : int
+  x*x
+fun square5tour/square5: (x : int) -> int( xx: int : intstd/core/types/int: V )result: -> total int : intstd/core/types/int: V
+  xx: int*std/core/int/(*): (int, int) -> intxx: int
+
+ + + +

the assumed effect is totalstd/core/types/total: E. Sometimes, we write an effectful +function, but are not interested in explicitly writing down its effect type. +In that case, we can use a wildcard type which stands for some inferred +type. A wildcard type is denoted by writing an identifier prefixed with an +underscore, or even just an underscore by itself: +

fun square6( x : int ) : _e int
+  println("I did not want to write down the \"console\" effect")
+  x*x
+fun square6tour/square6: (x : int) -> console int( xx: int : intstd/core/types/int: V )result: -> console int : _e_e: E intstd/core/types/int: V
+  printlnstd/core/console/string/println: (s : string) -> console ()("I did not want to write down the \"console\" effect"literal: string
count= 49
) + xx: int*std/core/int/(*): (int, int) -> console int
xx: int +
+ + + +

Hover over square6tour/square6: (x : int) -> console int to see the inferred effect for _e. +

3.2.1. Semantics of effects

+

The inferred effects are not just considered as some extra type information on +functions. On the contrary, through the inference of effects, Koka has a very +strong connection to its denotational semantics. In particular, the full type +of a Koka functions corresponds directly to the type signature of the +mathematical function that describes its denotational semantics. For example, +using 〚t〛 to translate a type t into its corresponding +mathematical type signature, we have: +

+ + + +
intstd/core/types/int: V -> totalstd/core/types/total: E intstd/core/types/int: V =   $\mathpre{\mathbb{Z}~\rightarrow \mathbb{Z}}$
intstd/core/types/int: V -> exnstd/core/exn/exn: (E, V) -> V intstd/core/types/int: V = $\mathpre{\mathbb{Z}~\rightarrow (\mathbb{Z}~+~1)}$
intstd/core/types/int: V -> purestd/core/pure: E intstd/core/types/int: V = $\mathpre{\mathbb{Z}~\rightarrow (\mathbb{Z}~+~1)_\bot}$
intstd/core/types/int: V -> <ststd/core/types/st: H -> E<h>,purestd/core/pure: E> intstd/core/types/int: V = $\mathpre{(\mathbb{Z}~\times \mathbb{H})~\rightarrow ((\mathbb{Z}~+~1)~\times \mathbb{H})_\bot}$
+

In the above translation, we use $\mathpre{1~+~\tau}$ as a sum +where we have either a unit $\mathpre{1}$ (i.e. exception) or a type $\mathpre{\tau}$, and we use +$\mathpre{\mathbb{H}\times \tau}$ for a product consisting of a pair of a +heap and a type $\mathpre{\tau}$. From the above correspondence, we can immediately see that +a totalstd/core/types/total: E function is truly total in the mathematical sense, while a stateful +function (ststd/core/types/st: H -> E<h>) that can raise exceptions or not terminate (purestd/core/pure: E) +takes an implicit heap parameter, and either does not terminate ($\mathpre{\bot}$) or +returns an updated heap together with either a value or an exception ($\mathpre{1}$). +

+

We believe that this semantic correspondence is the true power of full effect +types and it enables effective equational reasoning about the code by a +programmer. For almost all other existing programming languages, even the most +basic semantics immediately include complex effects like heap manipulation and +divergence. In contrast, Koka allows a layered semantics where we can easily +separate out nicely behaved parts, which is essential for many domains, like +safe LINQ queries, parallel tasks, tier-splitting, sand-boxed mobile code, +etc. +

3.2.2. Combining effects

+

Often, a function contains multiple effects, for example: +

fun combine-effects()
+  val i = srandom-int() // non-deterministic
+  throw("oops")         // exception raising
+  combine-effects()     // and non-terminating
+fun combine-effectstour/combine-effects: forall<a> () -> <pure,ndet> a()result: -> <exn,ndet,div> _5392
+  val ii: int = srandom-intstd/num/random/srandom-int: () -> <ndet,exn,div> int() // non-deterministic
+  throwstd/core/exn/throw: (message : string, info : ? exception-info) -> <exn,ndet,div> _5402("oops"literal: string
count= 4
) // exception raising + combine-effectstour/combine-effects: () -> <exn,ndet,div> _5392(
) // and non-terminating +
+ + + +

The effect assigned to combine-effectstour/combine-effects: forall<a> () -> <pure,ndet> a are ndetstd/core/types/ndet: X, divstd/core/types/div: X, and exnstd/core/exn/exn: (E, V) -> V. We +can write such combination as a row of effects as <divstd/core/types/div: X,exnstd/core/exn/exn: (E, V) -> V,ndetstd/core/types/ndet: X>. When +you hover over the combine-effectstour/combine-effects: forall<a> () -> <pure,ndet> a identifiers, you will see that the type +inferred is really <purestd/core/pure: E,ndetstd/core/types/ndet: X> where purestd/core/pure: E is a type alias defined as: +

alias pure = <div,exn>
+alias purestd/core/pure: E = <divstd/core/types/div: X,exnstd/core/exn/exn: (E, V) -> V>
+
+ + + +

3.2.3. Polymorphic effects

+

Many functions are polymorphic in their effect. For example, the +mapstd/core/list/map: forall<a,b,e> (xs : list<a>, f : (a) -> e b) -> e list<b> function +applies a function f to each element of a (finite) list. As such, the effect +depends on the effect of f, and the type of map becomes: +

map : (xs : list<a>, f : (a) -> e b) -> e list<b>
+map : (xs : liststd/core/types/list: V -> V<a>, f : (a) -> e b) -> e liststd/core/types/list: V -> V<b>
+
+ + + +

We use single letters (possibly followed by digits) for polymorphic types. +Here, the map functions takes a list with elements of some type a, and a +function f that takes an element of type a and returns a new element of +type b. The final result is a list with elements of type b. Moreover, +the effect of the applied function e is also the effect of the map +function itself; indeed, this function has no other effect by itself since it +does not diverge, nor raises exceptions. +

+

We can use the notation <l|e> to extend an effect e with another effect +l. This is used for example in the whilestd/core/while: forall<e> (predicate : () -> <div|e> bool, action : () -> <div|e> ()) -> <div|e> () function which has type: +whilestd/core/while: forall<e> (predicate : () -> <div|e> bool, action : () -> <div|e> ()) -> <div|e> () : ( pred : () -> <divstd/core/types/div: X|e> boolstd/core/types/bool: V, action : () -> <divstd/core/types/div: X|e> () ) -> <divstd/core/types/div: X|e> (). +The whilestd/core/while: forall<e> (predicate : () -> <div|e> bool, action : () -> <div|e> ()) -> <div|e> () function takes a +predicate function and an action to perform, both with effect <divstd/core/types/div: X|e>. +Indeed, since while may diverge depending on the predicate its effect must +include divergence. +

+

The reader may be worried that the type of whilestd/core/while: forall<e> (predicate : () -> <div|e> bool, action : () -> <div|e> ()) -> <div|e> () forces the predicate and +action to have exactly the same effect <divstd/core/types/div: X|e>, which even includes +divergence. However, when effects are inferred at the call-site, both the +effects of predicate and action are extended automatically until they match. +This ensures we take the union of the effects in the predicate and action. +Take for example the following loop: +

fun looptest()
+  while { is-odd(srandom-int()) }
+    throw("odd")
+fun looptesttour/looptest: () -> <pure,ndet> ()()result: -> <pure,ndet> ()
+  whilestd/core/while: (predicate : () -> <div,ndet,exn> bool, action : () -> <div,ndet,exn> ()) -> <div,ndet,exn> () { is-oddstd/core/int/is-odd: (i : int) -> <ndet,div,exn> bool(srandom-intstd/num/random/srandom-int: () -> <ndet,div,exn> int()) }
+    throwstd/core/exn/throw: (message : string, info : ? exception-info) -> <exn,div,ndet> ()("odd"literal: string
count= 3
) +
+ + + +

Koka infers that the predicate odd(srandom-int()) has +effect <ndetstd/core/types/ndet: X|e1> while the action has effect <exnstd/core/exn/exn: (E, V) -> V|e2> for some e1 and e2. +When applying whilestd/core/while: forall<e> (predicate : () -> <div|e> bool, action : () -> <div|e> ()) -> <div|e> (), those +effects are unified to the type <exnstd/core/exn/exn: (E, V) -> V,ndetstd/core/types/ndet: X,divstd/core/types/div: X|e3> for some e3. +

3.2.4. Local Mutable Variables

+

The Fibonacci numbers are a sequence where each subsequent Fibonacci number is +the sum of the previous two, where fibtour/fib: (n : int) -> div int(0) == 0 and fibtour/fib: (n : int) -> div int(1) == 1. We can +easily calculate Fibonacci numbers using a recursive function: +

fun main() { println(fib(10)) }
+
+fun fib(n : int) : div int
+  if n <= 0   then 0
+  elif n == 1 then 1
+  else fib(n - 1) + fib(n - 2)
+fun fibtour/fib: (n : int) -> div int(nn: int : intstd/core/types/int: V)result: -> div int : divstd/core/types/div: X intstd/core/types/int: V
+  if nn: int <=std/core/int/(<=): (x : int, y : int) -> div bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
then 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
+ elif nn: int ==std/core/int/(==): (x : int, y : int) -> div bool 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
then 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
+ else fibtour/fib: (n : int) -> div int(nn: int -std/core/int/(-): (x : int, y : int) -> div int 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
) +std/core/int/(+): (x : int, y : int) -> div int fibtour/fib: (n : int) -> div int(nn: int -std/core/int/(-): (x : int, y : int) -> div int 2literal: int
dec = 2
hex8 = 0x02
bit8 = 0b00000010
) +
+ + + +

Note that the type inference engine is currently not powerful enough to +prove that this recursive function always terminates, which leads to +inclusion of the divergence effect divstd/core/types/div: X in the result type. +

+

Here is another version of the Fibonacci function but this time +implemented using local mutable variables. +We use the repeat function to iterate n times: +

fun main() { println(fib2(10)) }
+
+fun fib2(n)
+  var x := 0
+  var y := 1
+  repeat(n)
+    val y0 = y
+    y := x+y
+    x := y0
+  x
+fun fib2tour/fib2: (n : int) -> int(nn: int)result: -> total int
+  var xx: local-var<$2650,int> := 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
+ var yy: local-var<$2650,int> := 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
+ repeatstd/core/repeat: (n : int, action : () -> (local<$2650>) ()) -> (local<$2650>) ()(nn: int) + val y0y0: int = yy: int + yy: local-var<$2650,int> :=std/core/types/local-set: (v : local-var<$2650,int>, assigned : int) -> (local<$2650>) () xx: int+std/core/int/(+): (x : int, y : int) -> (local<$2650>) intyy: int + xx: local-var<$2650,int> :=std/core/types/local-set: (v : local-var<$2650,int>, assigned : int) -> (local<$2650>) () y0y0: int +
xx: int +
+ + +

In contrast to a val declaration that binds an immutable value (as in val y0 = y), +a var declaration declares a mutable variable, where the (:=) operator +can assign a new value to the variable. Internally, the var declarations use +a state effect handler which ensures +that the state has the proper semantics even if resuming multiple times. +

+

However, that also means that mutable local variables are not quite first-class +and we cannot pass them as parameters to other functions for example (as they +are always dereferenced). The lifetime of mutable local variable cannot exceed +its lexical scope. For example, you get a type error if a local variable +escapes through a function expression: +

fun wrong() : (() -> console ())
+  var x := 1
+  (fn(){ x := x + 1; println(x) })
+fun wrong() : (() -> consolestd/core/console/console: X ())
+  var x := 1
+  (fn(){ x := x + 1; println(x) })
+
+ + +

This restriction allows for a clean semantics but also for (future) optimizations +that are not possible for general mutable reference cells. +

+

Read more about state and multiple resumptions

3.2.5. Reference Cells and Isolated state

+

Koka also has first-class heap allocated mutable reference cells. +A reference to an +integer is allocated using val r = refstd/core/types/ref: forall<a,h> (value : a) -> (alloc<h>) ref<h,a>(0) (since the reference itself is +actually a value!), and can be dereferenced using the bang operator, as !r. +We can write the Fibonacci function using reference cells as: +

fun main() { println(fib3(10)) }
+
+fun fib3(n)
+  val x = ref(0)
+  val y = ref(1)
+  repeat(n)
+    val y0 = !y
+    y := !x + !y
+    x := y0
+  !x
+fun fib3tour/fib3: (n : int) -> int(nn: int)result: -> total int
+  val xx: ref<_2791,int> = refstd/core/types/ref: (value : int) -> <alloc<_2791>,read<_2791>,write<_2791>> ref<_2791,int>(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) + val yy: ref<_2791,int> = refstd/core/types/ref: (value : int) -> <alloc<_2791>,read<_2791>,write<_2791>> ref<_2791,int>(1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
) + repeatstd/core/repeat: (n : int, action : () -> <read<_2791>,write<_2791>,alloc<_2791>> ()) -> <read<_2791>,write<_2791>,alloc<_2791>> ()(nn: int) + val y0y0: int = !std/core/types/ref/(!): (ref : ref<_2791,int>) -> <read<_2791>,write<_2791>,alloc<_2791>> intyy: ref<_2791,int> + yy: ref<_2791,int> :=std/core/types/set: (ref : ref<_2791,int>, assigned : int) -> <write<_2791>,read<_2791>,alloc<_2791>> () !std/core/types/ref/(!): (ref : ref<_2791,int>) -> <read<_2791>,write<_2791>,alloc<_2791>> intxx: ref<_2791,int> +std/core/int/(+): (x : int, y : int) -> <read<_2791>,write<_2791>,alloc<_2791>> int !std/core/types/ref/(!): (ref : ref<_2791,int>) -> <read<_2791>,write<_2791>,alloc<_2791>> intyy: ref<_2791,int> + xx: ref<_2791,int> :=std/core/types/set: (ref : ref<_2791,int>, assigned : int) -> <write<_2791>,read<_2791>,alloc<_2791>> () y0y0: int + !std/core/types/ref/(!): (ref : ref<_2791,int>) -> <read<_2791>,write<_2791>,alloc<_2791>> int
xx: ref<_2791,int> +
+ + + +

As we can see, using var declarations are generally preferred as these +behave better under multiple resumptions, but also are syntactically more +concise as they do not need a dereferencing operator. (Nevertheless, we +still need reference cells as those are first-class while var variables +cannot be passed to other functions.) +

+

When we look at the types inferred for the references, we see that x and y +have type refstd/core/types/ref: (H, V) -> V<h,intstd/core/types/int: V> which stands for a reference to a mutable value of +type intstd/core/types/int: V in some heap h. The effects on heaps are allocation as +heap<h>, reading from a heap as readstd/core/types/read: H -> X<h> and writing to a heap as +writestd/core/types/write: H -> X<h>. The combination of these effects is called stateful and denoted +with the alias ststd/core/types/st: H -> E<h>. +

+

Clearly, the effect of the body of fib3tour/fib3: (n : int) -> int is ststd/core/types/st: H -> E<h>; but when we hover over +fib3tour/fib3: (n : int) -> int, we see the type inferred is actually the totalstd/core/types/total: E effect: (n:intstd/core/types/int: V) -> intstd/core/types/int: V. +Indeed, even though fib3tour/fib3: (n : int) -> int is stateful inside, its side-effects can +never be observed. It turns out that we can safely discard the ststd/core/types/st: H -> E<h> +effect whenever the heap type h cannot be referenced outside this function, +i.e. it is not part of an argument or return type. More formally, the Koka +compiler proves this by showing that a function is fully polymorphic in the +heap type h and applies the runstd/core/types/run: forall<e,a> (action : forall<h> () -> <alloc<h>,read<h>,write<h>|e> a) -> e a function (corresponding to runST in +Haskell) to discard the ststd/core/types/st: H -> E<h> effect. +

+

The Garsia-Wachs algorithm is a nice example where side-effects are used +internally across function definitions and data structures, but where the +final algorithm itself behaves like a pure function, see the +samples/basic/garsia-wachs.kk. +

3.3. Data Types

3.3.1. Structs

+

An important aspect of a function-oriented language is to be able to define +rich data types over which the functions work. A common data type is that of a +struct or record. Here is an example of a struct that contains information +about a person: +

struct person
+  age : int
+  name : string
+  realname : string = name
+
+val brian = Person( 29, "Brian" )
+struct persontour/person: V
+  ageage: int : intstd/core/types/int: V
+  namename: string : stringstd/core/types/string: V
+  realnamerealname: string : stringstd/core/types/string: V = namename: string
+
+val briantour/brian: person = Persontour/Person: (age : int, name : string, realname : string) -> person( 29literal: int
dec = 29
hex8 = 0x1D
bit8 = 0b00011101
, "Brian"literal: string
count= 5
) +
+ + + +

Every struct (and other data types) come with constructor functions to +create instances, as in Persontour/Person: (age : int, name : string, realname : string) -> person(19,"Brian"). Moreover, these +constructors can use named arguments so we can also call the constructor +as Persontour/Person: (age : int, name : string, realname : string) -> person( name = "Brian", age = 19, realname = "Brian H. Griffin" ) +which is quite close to regular record syntax but without any special rules; +it is just functions all the way down! +

+

Also, Koka automatically generates accessor functions for each field in a +struct (or other data type), and we can access the age of a persontour/person: V as +briantour/brian: person.age (which is of course just syntactic sugar for age(briantour/brian: person)). +

3.3.2. Copying

+

By default, all structs (and other data types) are immutable. Instead of +directly mutating a field in a struct, we usually return a new struct where +the fields are updated. For example, here is a birthdaytour/birthday: (p : person) -> person function that +increments the age field: +

fun main()
+  println( brian.birthday.age )
+
+struct person
+  age : int
+  name : string
+  realname : string = name
+
+val brian = Person( 29, "Brian" )
+
+fun birthday( p : person ) : person
+  p( age = p.age + 1 )
+fun birthdaytour/birthday: (p : person) -> person( pp: person : persontour/person: V )result: -> total person : persontour/person: V
+  pp: person( age = pp: person.agetour/person/age: (person : person) -> int +std/core/int/(+): (x : int, y : int) -> int 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
) +
+ + + +

Here, birthdaytour/birthday: (p : person) -> person returns a fresh persontour/person: V which is equal to p but with the +age incremented. The syntax p(...) is syntactic sugar for calling the copy constructor of +a persontour/person: V. This constructor is also automatically generated for each data +type, and is internally generated as: +

fun main()
+  println( brian.copy().age )
+
+struct person( age : int, name : string, realname : string = name )
+
+val brian = Person( 29, "Brian" )
+
+fun copy( p, age = p.age, name = p.name, realname = p.realname )
+  Person(age, name, realname)
+fun copytour/copy: (p : person, age : ? int, name : ? string, realname : ? string) -> person( pp: person, ageage: ? int = pp: person.agetour/person/age: (person : person) -> int, namename: ? string = pp: person.nametour/person/name: (person : person) -> string, realnamerealname: ? string = pp: person.realnametour/person/realname: (person : person) -> string )result: -> total person
+  Persontour/Person: (age : int, name : string, realname : string) -> person(ageage: int, namename: string, realnamerealname: string)
+
+ + + +

When arguments follow a data value, as in p( age = p.age + 1), it is expanded to call this +copy function, as in p.copytour/copy: (p : person, age : ? int, name : ? string, realname : ? string) -> person( age = p.age + 1 ). In adherence with the min-gen principle, +there are no special rules for record updates but using plain function calls with optional +and named parameters. +

3.3.3. Alternatives (or Unions)

+

Koka also supports algebraic data types where there are multiple alternatives. +For example, here is an enumeration: +

type color
+  Red
+  Green
+  Blue
+type color
+  Red
+  Green
+  Blue
+
+ + + +

Special cases of these enumerated types are the voidstd/core/types/void: V type which has no +alternatives (and therefore there exists no value with this type), the unit +type (()) which has just one constructor, also written as () (and +therefore, there exists only one value with the type (()), namely ()), and +finally the boolean type boolstd/core/types/bool: V with two constructors Truestd/core/types/True: bool and Falsestd/core/types/False: bool. +

type void
+
+type ()
+  ()
+
+type bool
+  False
+  True
+type voidstd/core/types/void: V
+
+type ()
+  ()
+
+type boolstd/core/types/bool: V
+  Falsestd/core/types/False: bool
+  Truestd/core/types/True: bool
+
+ + + +

Constructors can have parameters. For example, here is how to create a +number type which is either an integer or the infinity value: +

type number
+  Infinity
+  Integer( i : int )
+type number
+  Infinity
+  Integer( i : intstd/core/types/int: V )
+
- - - - -book documentation - +

We can create such number by writing Integer(1) or Infinity. Moreover, +data types can be polymorphic and recursive. Here is the definition of the +liststd/core/types/list: V -> V type which is either empty (Nilstd/core/types/Nil: forall<a> list<a>) or is a head element followed by a +tail list (Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>): +

type list<a>
+  Nil
+  Cons{ head : a; tail : list<a> }
+type liststd/core/types/list: V -> V<a>
+  Nilstd/core/types/Nil: forall<a> list<a>
+  Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>{ head : a; tail : liststd/core/types/list: V -> V<a> }
+
- -

book▲toc

-
-

+

Koka automatically generates accessor functions for each named parameter. For +lists for example, we can access the head of a list as Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(1,Nilstd/core/types/Nil: forall<a> list<a>).head. +

+

We can now also see that struct types are just syntactic sugar for a regular +type with a single constructor of the same name as the type: +

+
+

translation

+
struct tp { <fields> }
+struct tp { <fields> }
+
+ + +

$\mathpre{\rightsquigarrow}$ +

type tp {
+  Tp { <fields> }
+}
+type tp {
+  Tp { <fields> }
+}
+
+
+

For example, +our earlier persontour/person: V struct, defined as +

struct person{ age : int; name : string; realname : string = name }
+struct persontour/person: V{ age : intstd/core/types/int: V; name : stringstd/core/types/string: V; realname : stringstd/core/types/string: V = name }
+
+ + + +

desugars to: +

type person
+  Person{ age : int; name : string; realname : string = name }
+type persontour/person: V
+  Persontour/Person: (age : int, name : string, realname : string) -> person{ age : intstd/core/types/int: V; name : stringstd/core/types/string: V; realname : stringstd/core/types/string: V = name }
+
+ + + +

or with brace elision as: +

type person
+  Person
+    age : int
+    name : string
+    realname : string = name
+type persontour/person: V
+  Persontour/Person: (age : int, name : string, realname : string) -> person
+    age : intstd/core/types/int: V
+    name : stringstd/core/types/string: V
+    realname : stringstd/core/types/string: V = name
+
+ + +

3.3.4. Matching

+

Todo +

3.3.5. Extensible Data Types

+

Todo +

3.3.6. Inductive, Co-inductive, and Recursive Types

+

For the purposes of equational reasoning and termination checking, a type +declaration is limited to finite inductive types. There are two more +declarations, namely co type and rec type that allow for co-inductive types, +and arbitrary recursive types respectively. +

3.3.7. Value Types

+

Value types are (non-recursive) data types that are not heap allocated +but passed on the stack as a value. Since data types are immutable, semantically +these types are equivalent but value types can be more efficient as they +avoid heap allocation and reference counting (or more expensive as they need copying +instead of sharing a reference). +

+

By default, any non-recursive inductive data type of a size up to 3 machine words (= 24 bytes +on a 64-bit platform) is treated as a value type. For example, tuples and 3-tuples +are passed and returned by value. Usually, that means that such tuples are for +example returned in registers when compiling with optimization. +

+

We can also force a type to be compiled as a value type by using the value keyword +in front of a type or struct declaration: +

value struct argb{ alpha: int; color-red: int; color-green: int; color-blue: int }
+value struct argbtour/argb: V{ alphatour/argb/alpha: (argb : argb) -> int: intstd/core/types/int: V; color-redtour/argb/color-red: (argb : argb) -> int: intstd/core/types/int: V; color-greentour/argb/color-green: (argb : argb) -> int: intstd/core/types/int: V; color-bluetour/argb/color-blue: (argb : argb) -> int: intstd/core/types/int: V }
+
+ + + +
+

advanced +

Boxing

+

To support generic polymorphism, sometimes value types are boxed. For example, a list +is polymorphic in its elements. That means that if we construct a list of tuples, like +[(1,Truestd/core/types/True: bool)], that the element (1,2) will be boxed and heap allocated – essentially +the compiler transforms this expression into [Boxstd/core/types/Box: forall<a> (unbox : a) -> box<a>((1,Truestd/core/types/True: bool)] internally. +

+

Note that for regular data types and intstd/core/types/int: V's boxing is free (as in isomorphic). Moreover, value types +up to 63 bits (on a 64-bit platform) are boxed in-place and do not require heap allocation +(like int32std/core/types/int32: V). The float64std/core/types/float64: V type is also specialized; by default the Koka compiler +only heap allocates float64std/core/types/float64: Vs when their absolute value is +outside the range 2-511 up to 2512 (excluding infinity and NaN)). +

+

For performance sensitive code we may specialize certain polymorphic data types to +reduce allocations due to boxing. For example: +

type mylist
+  MyCons{ head1: int; head2: bool; mytail: mylist }
+  MyNil
+type mylisttour/mylist: V
+  MyConstour/MyCons: (head1 : int, head2 : bool, mytail : mylist) -> mylist{ head1: intstd/core/types/int: V; head2: boolstd/core/types/bool: V; mytail: mylisttour/mylist: V }
+  MyNiltour/MyNil: mylist
+
+ + + +

Our previous example becomes MyConstour/MyCons: (head1 : int, head2 : bool, mytail : mylist) -> mylist(1,Truestd/core/types/True: bool,MyNiltour/MyNil: mylist) now and is more efficient as it only needs +one allocation for the MyConstour/MyCons: (head1 : int, head2 : bool, mytail : mylist) -> mylist without an indirection to a tuple. +In the future we hope to extend Koka to perform specialization automatically or by +using special directives. +

3.4. Effect Handlers

+

Effect handlers [9, 10, 21] are a novel way to +define control-flow abstractions and dynamic binding as user defined +handlers – no need anymore to add special compiler extensions for +exceptions, iterators, async-await, probabilistic programming, etc. +Moreover, these handlers can be composed freely so the interaction between, +say, async-await and exceptions are well-defined. +

3.4.1. Handling

+

Let's start with defining an exception effect of our own. The effect +declaration defines a new type together with operations, for now +we use the most general control (ctl) operation: +

effect raise
+  ctl raise( msg : string ) : a
+effecttour/raise: (E, V) -> V raisetour/raise: (E, V) -> V
+  ctl raise( msgmsg: string : stringstd/core/types/string: V ) : aa: V
+
+ + + +

This defines an effect type raisetour/raise: (E, V) -> V together with an operation +raisetour/raise: forall<a> (msg : string) -> raise a of type (msg : stringstd/core/types/string: V) -> raisetour/raise: (E, V) -> V a. With the effect signature +declared, we can already use the operations: +

fun safe-divide( x : int, y : int ) : raise int
+  if y==0 then raise("div-by-zero") else x / y
+fun safe-dividetour/safe-divide: (x : int, y : int) -> raise int( xx: int : intstd/core/types/int: V, yy: int : intstd/core/types/int: V )result: -> raise int : raisetour/raise: (E, V) -> V intstd/core/types/int: V
+  if yy: int==std/core/int/(==): (x : int, y : int) -> raise bool0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
then raisetour/raise: (msg : string) -> raise int("div-by-zero"literal: string
count= 11
) else xx: int /std/core/int/(/): (x : int, y : int) -> raise int
yy: int +
+ + +

where we see that the safe-dividetour/safe-divide: (x : int, y : int) -> raise int function gets the raisetour/raise: (E, V) -> V effect +(since we use the raisetour/raise: forall<a> (msg : string) -> raise a operation in the body). Such an effect +type means that we can only evaluate the function in a context +where raisetour/raise: (E, V) -> V is handled (in other words, where it is “dynamically bound”, or +where we “have the raisetour/raise: (E, V) -> V capability”). +

+

We can handle the effect by giving a concrete definition for the raisetour/raise: forall<a> (msg : string) -> raise a operation. +For example, we may always return a default value: +

fun raise-const() : int
+  with handler
+    ctl raise(msg) 42
+  8 + safe-divide(1,0)
+fun raise-consttour/raise-const: () -> int()result: -> total int : intstd/core/types/int: V
+  withwith: () -> raise int handlerhandler: (() -> raise int) -> int
+    ctl raiseraise: (msg : string, resume : (_7968) -> int) -> int
(msgmsg: string) 42literal: int
dec = 42
hex8 = 0x2A
bit8 = 0b00101010
+ 8literal: int
dec = 8
hex8 = 0x08
bit8 = 0b00001000
+std/core/int/(+): (x : int, y : int) -> raise int safe-dividetour/safe-divide: (x : int, y : int) -> raise int(1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
,0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) +
+ + +

The call raise-consttour/raise-const: () -> int() evaluates to 42 (not 50). +When a raisetour/raise: forall<a> (msg : string) -> raise a is called (in safe-dividetour/safe-divide: (x : int, y : int) -> raise int), it will yield to its innermost handler, unwind +the stack, and only then evaluate the operation definition – in this case just directly +returning 42 from the point where the handler is defined. +Now we can see why it is called a control +operation as raisetour/raise: forall<a> (msg : string) -> raise a changes the regular linear control-flow and yields right +back to its innermost handler from the original call site. +Also note that raise-consttour/raise-const: () -> int is totalstd/core/types/total: E again and the handler discharged the +raisetour/raise: (E, V) -> V effect. +

+

The handler{ <ops> } expression is a function that itself expects a function +argument over which the handler is scoped, as in (handler{ <ops> })(action). +This works well in combination with the with statement of course. +As a syntactic convenience, for single operations we can leave out the handler keyword +which is translated as: +

+
+

translation

+
with ctl op(<args>){ <body> }
+with ctl op(<args>){ <body> }
+
+ + +

$\mathpre{\rightsquigarrow}$ +

with handler
+  ctl op(<args>){ <body> }
+with handler
+  ctl op(<args>){ <body> }
+
+
+

With this translation, we can write the previous example more concisely as: +

fun raise-const1() : int
+  with ctl raise(msg) 42
+  8 + safe-divide(1,0)
+fun raise-const1tour/raise-const1: () -> int()result: -> total int : intstd/core/types/int: V
+  withhandler: (() -> raise int) -> int ctl raiseraise: (msg : string, resume : (_8047) -> int) -> int
(msgmsg: string) 42literal: int
dec = 42
hex8 = 0x2A
bit8 = 0b00101010
+ 8literal: int
dec = 8
hex8 = 0x08
bit8 = 0b00001000
+std/core/int/(+): (x : int, y : int) -> raise int safe-dividetour/safe-divide: (x : int, y : int) -> raise int(1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
,0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) +
+ + + +

which eventually expands to (handler{ ctl raisetour/raise: forall<a> (msg : string) -> raise a(msg){ 42 } })(fn(){ 8 + safe-dividetour/safe-divide: (x : int, y : int) -> raise int(1,0) }). +

+

We have a similar syntactic convenience for effects with one operation where the +name of the effect and operation are the same. We can define such an effect by just declaring +its operation which implicitly declares an effect type of the same name: +

+
+

translation

+
effect ctl op(<parameters>) : <result-type>
+effect ctl op(<parameters>) : <result-type>
+
+ + +

$\mathpre{\rightsquigarrow}$ +

effect op {
+  ctl op(<parameters>) : <result-type>
+}
+effect op {
+  ctl op(<parameters>) : <result-type>
+}
+
+
+

That means we can declare our raisetour/raise: (E, V) -> V effect signature also more concisely as: +

effect ctl raise( msg : string ) : a
+effect ctl raisetour/raise: forall<a> (msg : string) -> raise a( msg : stringstd/core/types/string: V ) : a
+
+ + + +

+

+

Read more about the with statement

3.4.2. Resuming

+

The power of effect handlers is not just that we can yield to the innermost +handler, but that we can also resume back to the call site with a result. +

+

Let's define a asktour/ask: (V, E, V) -> V<a> effect that allows us to get a contextual value of type a: +

effect ask<a>                   // or: effect<a> ctl ask() : a
+  ctl ask() : a
+
+fun add-twice() : ask<int> int
+  ask() + ask()
+effecttour/ask: (V, E, V) -> V asktour/ask: (V, E, V) -> V<aa: V>                   // or: effect<a> ctl ask() : a
+  ctl ask() : aa: V
+
+fun add-twicetour/add-twice: () -> (ask<int>) int()result: -> (ask<int>) int : asktour/ask: (V, E, V) -> V<intstd/core/types/int: V> intstd/core/types/int: V
+  asktour/ask: () -> (ask<int>) int() +std/core/int/(+): (x : int, y : int) -> (ask<int>) int asktour/ask: () -> (ask<int>) int()
+
+ + + +

The add-twicetour/add-twice: () -> (ask<int>) int function can ask for numbers but it is unaware of how these +are provided – the effect signature just specifies an contextual API. +We can handle it by always resuming with a constant for example: +

fun ask-const() : int
+  with ctl ask() resume(21)
+  add-twice()
+fun ask-consttour/ask-const: () -> int()result: -> total int : intstd/core/types/int: V
+  withhandler: (() -> (ask<int>) int) -> int ctl askask: (resume : (int) -> int) -> int
() resumeresume: (int) -> int(21literal: int
dec = 21
hex8 = 0x15
bit8 = 0b00010101
) + add-twicetour/add-twice: () -> (ask<int>) int(
) +
+ + + +

where ask-consttour/ask-const: () -> int() evaluates to 42. Or by returning random values, like: +

fun ask-random() : random int
+  with ctl ask() resume(random-int())
+  add-twice()
+fun ask-randomtour/ask-random: () -> random int()result: -> random int : randomstd/num/random/random: (E, V) -> V intstd/core/types/int: V
+  withhandler: (() -> <ask<int>,random> int) -> random int ctl askask: (resume : (int) -> random int) -> random int
() resumeresume: (int) -> random int(random-intstd/num/random/random-int: () -> random int()) + add-twicetour/add-twice: () -> <ask<int>,random> int(
) +
+ + + +

where ask-randomtour/ask-random: () -> random int() now handled the asktour/ask: (V, E, V) -> V<intstd/core/types/int: V> effect, but itself now has +randomstd/num/random/random: (E, V) -> V effect (see std/num/random). +The resumestd/core/hnd/resume: forall<a,e,e1,b> (r : resume-context<a,e,e1,b>, x : a) -> e b function is implicitly bound by a ctl operation and resumes +back to the call-site with the given result. +

+

As we saw in the exception example, we do +not need to call resumestd/core/hnd/resume: forall<a,e,e1,b> (r : resume-context<a,e,e1,b>, x : a) -> e b and can also directly return into our handler scope. For example, we +may only want to handle a asktour/ask: forall<a> () -> (ask<a>) a once, but after that give up: +

fun ask-once() : int
+  var count := 0
+  with ctl ask()
+    count := count + 1
+    if count <= 1 then resume(42) else 0
+  add-twice()
+fun ask-oncetour/ask-once: () -> int()result: -> total int : intstd/core/types/int: V
+  var countcount: local-var<$3982,int> := 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
+ withhandler: (() -> <ask<int>,local<$3982>> int) -> (local<$3982>) int ctl askask: (resume : (int) -> (local<$3982>) int) -> (local<$3982>) int
() + countcount: local-var<$3982,int> :=std/core/types/local-set: (v : local-var<$3982,int>, assigned : int) -> (local<$3982>) () countcount: int +std/core/int/(+): (x : int, y : int) -> (local<$3982>) int 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
+ if countcount: int <=std/core/int/(<=): (x : int, y : int) -> (local<$3982>) bool 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
then resumeresume: (int) -> (local<$3982>) int(42literal: int
dec = 42
hex8 = 0x2A
bit8 = 0b00101010
) else 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
+ add-twicetour/add-twice: () -> (ask<int>) int(
) +
+ + + +

Here ask-oncetour/ask-once: () -> int() evaluates to 0 since the second call to asktour/ask: forall<a> () -> (ask<a>) a does not resume, +(and returns directly 0 in the ask-oncetour/ask-once: () -> int context). This pattern can for example +be used to implement the concept of fuel in a setting where a computation is +only allowed to take a limited amount of steps. +

+

Read more about var mutable variables

3.4.3. Tail-Resumptive Operations

+

A ctl operation is one of the most general ways to define operations since +we get a first-class resumestd/core/hnd/resume: forall<a,e,e1,b> (r : resume-context<a,e,e1,b>, x : a) -> e b function. However, almost all operations in practice turn out +to be tail-resumptive: that is, they resume exactly once with their final result +value. To make this more convenient, we can declare fun operations that do this +by construction, i.e. +

+
+

translation

+
with fun op(<args>){ <body> }
+with fun op(<args>){ <body> }
+
+ + +

$\mathpre{\rightsquigarrow}$ +

with ctl op(<args>){ val f = fn(){ <body> }; resume( f() ) }
+with ctl op(<args>){ val f = fn(){ <body> }; resumestd/core/hnd/resume: forall<a,e,e1,b> (r : resume-context<a,e,e1,b>, x : a) -> e b( f() ) }
+
+
+

(The translation is defined via an intermediate function f so return works as expected). +

+

With this syntactic sugar, we can write our earlier ask-consttour/ask-const: () -> int example +using a fun operation instead: +

fun ask-const2() : int
+  with fun ask() 21
+  add-twice()
+fun ask-const2tour/ask-const2: () -> int()result: -> total int : intstd/core/types/int: V
+  withhandler: (() -> (ask<int>) int) -> int fun askask: () -> int() 21literal: int
dec = 21
hex8 = 0x15
bit8 = 0b00010101
+ add-twicetour/add-twice: () -> (ask<int>) int(
) +
+ + + +

This also conveys better that even though asktour/ask: forall<a> () -> (ask<a>) a is dynamically bound, it behaves +just like a regular function without changing the control-flow. +

+

Moreover, operations declared as fun are much more efficient than general +ctl operations. The Koka compiler uses (generalized) evidence passing [2325] +to pass down handler information to each call-site. At the call to asktour/ask: forall<a> () -> (ask<a>) a in add-twicetour/add-twice: () -> (ask<int>) int, +it selects the handler from the evidence vector and when the operation is +a tail-resumptive fun, it calls it directly as a regular function (except with an adjusted evidence +vector for its context). Unlike a general ctl operation, there is no need to yield upward +to the handler, capture the stack, and eventually resume again. +This gives fun (and val) operations a performance cost very similar to virtual method calls +which can be quite efficient. +

+

For even a bit more performance, you can also declare upfront that any operation +definition must be tail-resumptive, as: +

effect ask<a>
+  fun ask() : a
+effect asktour/ask: (V, E, V) -> V<a>
+  fun asktour/ask: forall<a> () -> (ask<a>) a() : a
+
+ + + +

This restricts all handler definitions for the asktour/ask: (V, E, V) -> V effect to use fun definitions +for the asktour/ask: forall<a> () -> (ask<a>) a operation. However, it increases the ability to reason about the code, +and the compiler can optimize such calls a bit more as it no longer needs to check at +run-time if the handler happens to define the operation as tail-resumptive. +

+
+

advancedFor even better performance, one can mark the effect as linear (Section 3.4.12). +Such effects are statically guaranteed to never use a general control operation and +never need to capture a resumption. During compilation, this removes the need for the monadic transformation +and improves performance of any effect polymorphic function that uses such effects as well +(like map or foldrstd/core/list/foldr: forall<a,b,e> (xs : list<a>, z : b, f : (a, b) -> e b) -> e b). Examples of linear effects are state (ststd/core/types/st: H -> E) and builtin effects +(like iostd/core/io: E or consolestd/core/console/console: X).

Value Operations

+

A common subset of operations always tail-resume with a single value; these are +essentially dynamically bound variables (but statically typed!). Such operations +can be declared as a val with the following translation: +

+
+

translation

+
with val v = <expr>
+with val v = <expr>
+
+ + +

$\mathpre{\rightsquigarrow}$ +

val x = <expr>
+with fun v(){ x }
+val x = <expr>
+with fun v(){ x }
+
+ + +

$\mathpre{\rightsquigarrow}$ +

val x = <expr>
+with ctl v(){ resume(x) }
+val x = <expr>
+with ctl v(){ resumestd/core/hnd/resume: forall<a,e,e1,b> (r : resume-context<a,e,e1,b>, x : a) -> e b(x) }
+
+
+

For an example of the use of value operations, consider a +pretty printer that produces pretty strings from documents: +

fun pretty( d : doc ) : string
+fun prettytour/pretty: (d : doc) -> width string( d : doctour/doc: V ) : stringstd/core/types/string: V
+
+ + + +

Unfortunately, it has a hard-coded maximum display width of 40 deep +down in the code of prettytour/pretty: (d : doc) -> width string: +

fun pretty-internal( line : string ) : string
+  line.truncate(40)
+fun pretty-internaltour/pretty-internal: (line : string) -> width string( line : stringstd/core/types/string: V ) : stringstd/core/types/string: V
+  line.truncate(40)
+
+ + + +

To abstract over the width we have a couple of choices: we +could make the width a regular parameter but now we need to +explicitly add the parameter to all functions in the library +and manually thread them around. Another option is a global +mutable variable but that leaks side-effects and is non-modular. +

+

Or, we can define it as a value operation instead: +

effect val width : int
+effecttour/width: (E, V) -> V val widthtour/width: (E, V) -> V : intstd/core/types/int: V
+
+ + + +

This also allows us to refer to the widthtour/width: -> width int operation as if it was a +regular value (even though internally it invokes the operation). +So, the check for the width in the pretty printer can be written as: +

fun pretty-internal( line : string ) : width string
+  line.truncate(width)
+fun pretty-internaltour/pretty-internal: (line : string) -> width string( lineline: string : stringstd/core/types/string: V )result: -> width string : widthtour/width: (E, V) -> V stringstd/core/types/string: V
+  lineline: string.truncatestd/core/sslice/string/truncate: (s : string, count : int) -> width string(widthtour/width: -> width int)
+
+ + + +

When using the pretty printer we can bind the widthtour/width: -> width int as a +regular effect handler: +

fun pretty-thin(d : doc) : string
+  with val width = 40
+  pretty(d)
+fun pretty-thintour/pretty-thin: (d : doc) -> string(dd: doc : doctour/doc: V)result: -> total string : stringstd/core/types/string: V
+  withhandler: (() -> width string) -> string val widthwidth: () -> int = 40literal: int
dec = 40
hex8 = 0x28
bit8 = 0b00101000
+ prettytour/pretty: (d : doc) -> width string(dd: doc
) +
+ + + +

Note that we did not need to change the structure of the +original library functions. However the types of the functions +still change to include the widthtour/width: (E, V) -> V effect as these now +require the widthtour/width: -> width int value to be handled at some point. +For example, the type of prettytour/pretty: (d : doc) -> width string becomes: +

fun pretty( d : doc ) : width string
+fun prettytour/pretty: (d : doc) -> width string( d : doctour/doc: V ) : widthtour/width: (E, V) -> V stringstd/core/types/string: V
+
+ + +

as is requires the widthtour/width: (E, V) -> V effect to be handled (aka, +the "dynamic binding for widthtour/width: -> width int : intstd/core/types/int: V to be defined“, +aka, the ”widthtour/width: (E, V) -> V capability"). +

3.4.4. Abstracting Handlers

+

As another example, a writer effect is quite common where +values are collected by a handler. For example, we can +define an emittour/emit: (E, V) -> V effect to emit messages: +

effect fun emit( msg : string ) : ()
+effect fun emittour/emit: (msg : string) -> emit ()( msg : stringstd/core/types/string: V ) : ()
+
+ + +
fun ehello() : emit ()
+  emit("hello")
+  emit("world")
+fun ehellotour/ehello: () -> emit ()()result: -> emit () : emittour/emit: (E, V) -> V (std/core/types/unit: V)std/core/types/unit: V
+  emittour/emit: (msg : string) -> emit ()("hello"literal: string
count= 5
) + emittour/emit: (msg : string) -> emit ()("world"literal: string
count= 5
) +
+ + + +

We can define for example a handler that prints the +emitted messages directly to the console: +

fun ehello-console() : console ()
+  with fun emit(msg) println(msg)
+  ehello()
+fun ehello-consoletour/ehello-console: () -> console ()()result: -> console () : consolestd/core/console/console: X (std/core/types/unit: V)std/core/types/unit: V
+  withhandler: (() -> <emit,console> ()) -> console () fun emitemit: (msg : string) -> console ()(msgmsg: string) printlnstd/core/console/string/println: (s : string) -> console ()(msgmsg: string)
+  ehellotour/ehello: () -> <emit,console> ()()
+
+ + + +

Here the handler is defined directly, but we can also abstract the handler for +emitting to the console into a separate function: +

fun emit-console( action )
+  with fun emit(msg) println(msg)
+  action()
+fun emit-consoletour/emit-console: forall<a,e> (action : () -> <console,emit|e> a) -> <console|e> a( actionaction: () -> <console,emit|_6128> _6044 )result: -> <console|13268> 13184
+  withhandler: (() -> <emit,console|_6128> _6044) -> <console|_6128> _6044 fun emitemit: (msg : string) -> <console|_6128> ()(msgmsg: string) printlnstd/core/console/string/println: (s : string) -> <console|_6128> ()(msgmsg: string)
+  actionaction: () -> <console,emit|_6128> _6044()
+
+ + + +

where emit-consoletour/emit-console: forall<a,e> (action : () -> <console,emit|e> a) -> <console|e> a has the inferred type (action : () -> <emittour/emit: (E, V) -> V,consolestd/core/console/console: X|e> a) -> <consolestd/core/console/console: X|e> a (hover +over the source to see the inferred types) where +the action can have use the effects emittour/emit: (E, V) -> V, consolestd/core/console/console: X, and any other effects e, +and where the final effect is just <consolestd/core/console/console: X|e> as the emittour/emit: (E, V) -> V effect +is discharged by the handler. +

+

Note, we could have written the above too as: +

val emit-console2 = handler
+  fun emit(msg) println(msg)
+val emit-console2tour/emit-console2: forall<a,e> (() -> <console,emit|e> a) -> <console|e> a = handlerhandler: forall<a,e> (() -> <console,emit|e> a) -> <console|e> a
+  fun emitemit: (msg : string) -> <console|_6245> ()(msgmsg: string) printlnstd/core/console/string/println: (s : string) -> <console|_6245> ()(msgmsg: string)
+
+ + +

since a handler{ ... } expression is a function itself (and thus a value). +Generally we prefer the earlier definition though as it allows further parameters +like an initial state. +

+

Since with works generally, we can use the abstracted handlers just like +regular handlers, and our earlier example can be written as: +

fun ehello-console2() : console ()
+  with emit-console
+  ehello()
+fun ehello-console2tour/ehello-console2: () -> console ()()result: -> console () : consolestd/core/console/console: X (std/core/types/unit: V)std/core/types/unit: V
+  withwith: () -> <console,emit> () emit-consoletour/emit-console: (action : () -> <console,emit> ()) -> console ()
+  ehellotour/ehello: () -> <emit,console> ()()
+
+ + +

(which expands to emit-consoletour/emit-console: forall<a,e> (action : () -> <console,emit|e> a) -> <console|e> a( fn(){ ehellotour/ehello: () -> emit ()() } )). +Another useful handler may collect all emitted messages as a list of lines: +

fun emit-collect( action : () -> <emit|e> () ) : e string
+  var lines := []
+  with handler
+    return(x)     lines.reverse.join("\n")
+    fun emit(msg) lines := Cons(msg,lines)
+  action()
+
+fun ehello-commit() : string
+  with emit-collect
+  ehello()
+fun emit-collecttour/emit-collect: forall<e> (action : () -> <emit|e> ()) -> e string( actionaction: () -> <emit|$5645> () : () -> <emittour/emit: (E, V) -> V|std/core/types/effect-extend: (X, E) -> Eee: E> (std/core/types/unit: V)std/core/types/unit: V )result: -> 5928 string : ee: E stringstd/core/types/string: V
+  var lineslines: local-var<$5654,list<string>> := [std/core/types/Nil: forall<a> list<a>]std/core/types/Nil: forall<a> list<a>
+  withwith: () -> <emit|$5645> () handlerhandler: (() -> <emit,local<$5654>|$5645> ()) -> <local<$5654>|$5645> string
+    returnreturn: (x : _5672) -> <local<$5654>|_5692> string(xx: _5672)     lineslines: list<string>.reversestd/core/list/reverse: (xs : list<string>) -> <local<$5654>|_5692> list<string>.joinstd/core/list/joinsep/join: (xs : list<string>, sep : string) -> <local<$5654>|_5692> string("\n"literal: string
count= 1
) + fun emitemit: (msg : string) -> <local<$5654>|$5645> ()(msgmsg: string) lineslines: local-var<$5654,list<string>> :=std/core/types/local-set: (v : local-var<$5654,list<string>>, assigned : list<string>) -> <local<$5654>|$5645> () Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(msgmsg: string,lineslines: list<string>) + actionaction: () -> <emit|$5645> ()(
) + +fun ehello-committour/ehello-commit: () -> string()result: -> total string : stringstd/core/types/string: V + withwith: () -> emit () emit-collecttour/emit-collect: (action : () -> emit ()) -> string + ehellotour/ehello: () -> emit ()() +
+ + + +

This is a total handler and only discharges the emittour/emit: (E, V) -> V effect. +

+

Read more about the with statement

+

Read more about var mutable variables

+

As another example, consider a generic catch handler that +applies an handling function when raisetour/raise: (E, V) -> V is called on our +exception example: +

fun catch( hnd : (string) -> e a, action : () -> <raise|e> a ) : e a
+  with ctl raise(msg) hnd(msg)
+  action()
+fun catchtour/catch: forall<a,e> (hnd : (string) -> e a, action : () -> <raise|e> a) -> e a( hndhnd: (string) -> $4399 $4398 : (stringstd/core/types/string: V) -> ee: E aa: V, actionaction: () -> <raise|$4399> $4398 : () -> <raisetour/raise: (E, V) -> V|std/core/types/effect-extend: (X, E) -> Eee: E> aa: V )result: -> 4474 4473 : ee: E aa: V
+  withhandler: (() -> <raise|$4399> $4398) -> $4399 $4398 ctl raiseraise: (msg : string, resume : (_4405) -> $4399 $4398) -> $4399 $4398
(msgmsg: string) hndhnd: (string) -> $4399 $4398(msgmsg: string) + actionaction: () -> <raise|$4399> $4398(
) +
+ + + +

We can use it now conveniently with a with statement to handle +exceptional situations: +

fun catch-example()
+  with catch( fn(msg){ println("error: " ++ msg); 42 } )
+  safe-divide(1,0)
+fun catch-exampletour/catch-example: () -> console int()result: -> console int
+  withwith: () -> <raise,console> int catchtour/catch: (hnd : (string) -> console int, action : () -> <raise,console> int) -> console int( fnfn: (msg : string) -> console int(msgmsg: string){ printlnstd/core/console/string/println: (s : string) -> console ()("error: "literal: string
count= 7
++std/core/types/(++): (x : string, y : string) -> console string msgmsg: string); 42literal: int
dec = 42
hex8 = 0x2A
bit8 = 0b00101010
} ) + safe-dividetour/safe-divide: (x : int, y : int) -> <raise,console> int(1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
,0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) +
+ + + +
+

advancedThe catch handler has an interesting type where the action can +have a raisetour/raise: (E, V) -> V effect (() -> <raisetour/raise: (E, V) -> V|e> a) and maybe further effects e, +while the handling function hnd only has effect e. Now consider +supplying a handing function that itself calls raisetour/raise: forall<a> (msg : string) -> raise a: in that case, the +type of catch would be instantiated to: (hnd: (stringstd/core/types/string: V) -> <raisetour/raise: (E, V) -> V> a, action : () -> <raisetour/raise: (E, V) -> V, raisetour/raise: (E, V) -> V> a ) : <raisetour/raise: (E, V) -> V> a. +This is correct: the (outer) raisetour/raise: (E, V) -> V effect of action is handled and discharged, but since +the handling function hnd can still cause raisetour/raise: forall<a> (msg : string) -> raise a to be called, the final effect still contains raisetour/raise: (E, V) -> V. +

+

Here we see that Koka allows duplicate effect labels [8] where action has +an instantiated <raisetour/raise: (E, V) -> V,raisetour/raise: (E, V) -> V> effect type. +These kind of types occur naturally in the presence of polymorphic effects, and there is a natural correspondence +to the structure of the evidence vectors at runtime (with entries for each nested effect handler). +Intuitively, the action effect expresses that +its outer (left-most) raisetour/raise: (E, V) -> V is handled, but that there may be other exceptions that are not handled – in this +case from the handling function hnd, but they can also be masked exceptions (as described in Section 3.4.7).

3.4.5. Return Operations

+

In the previous emit-collecttour/emit-collect: forall<e> (action : () -> <emit|e> ()) -> e string example we saw the use of +a return operation. Such operation changes the final +result of the action of a handler. +For example, consider our earlier used-defined exception effect raisetour/raise: (E, V) -> V. +We can define a general handler that transforms any exceptional +action into one that returns a maybestd/core/types/maybe: V -> V type: +

fun raise-maybe( action : () -> <raise|e> a ) : e maybe<a>
+  with handler
+    return(x)      Just(x)   // normal return: wrap in Just
+    ctl raise(msg) Nothing   // exception: return Nothing directly
+  action()
+
+
+fun div42()
+  (raise-maybe{ safe-divide(1,0) }).default(42)
+fun raise-maybetour/raise-maybe: forall<a,e> (action : () -> <raise|e> a) -> e maybe<a>( actionaction: () -> <raise|$5461> $5460 : () -> <raisetour/raise: (E, V) -> V|std/core/types/effect-extend: (X, E) -> Eee: E> aa: V )result: -> 5555 maybe<5554> : ee: E maybestd/core/types/maybe: V -> V<aa: V>
+  withwith: () -> <raise|$5461> $5460 handlerhandler: (() -> <raise|$5461> $5460) -> $5461 maybe<$5460>
+    returnreturn: (x : $5460) -> _5466 maybe<$5460>(xx: $5460)      Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: $5460)   // normal return: wrap in Just
+    ctl raiseraise: (msg : string, resume : (_5477) -> $5461 maybe<$5460>) -> $5461 maybe<$5460>
(msgmsg: string) Nothingstd/core/types/Nothing: forall<a> maybe<a> // exception: return Nothing directly + actionaction: () -> <raise|$5461> $5460(
) + + +fun div42tour/div42: () -> int()result: -> total int + (raise-maybetour/raise-maybe: (action : () -> raise int) -> maybe<int>{ safe-dividetour/safe-divide: (x : int, y : int) -> raise int(1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
,0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) }).defaultstd/core/maybe/default: (m : maybe<int>, nothing : int) -> int(42literal: int
dec = 42
hex8 = 0x2A
bit8 = 0b00101010
) +
+ + +

(where the body of div42tour/div42: () -> int desugars to default( raise-maybetour/raise-maybe: forall<a,e> (action : () -> <raise|e> a) -> e maybe<a>(fn(){ safe-dividetour/safe-divide: (x : int, y : int) -> raise int(1,0) }), 42 )). +

+

Read more about function block expressions

+

Read more about dot expressions

A State Effect

+

For more examples of the use of return operations, we look at a the state effect. +In its most general form it has just a set and gettour/get: forall<a> () -> (state<a>) a operation: +

effect state<a>
+  fun get() : a
+  fun set( x : a ) : ()
+
+fun sumdown( sum : int = 0 ) : <state<int>,div> int
+  val i = get()
+  if i <= 0 then sum else
+    set( i - 1 )
+    sumdown( sum + i )
+effecttour/state: (V, E, V) -> V statetour/state: (V, E, V) -> V<aa: V>
+  fun get() : aa: V
+  fun set( xx: $4881 : aa: V ) : (std/core/types/unit: V)std/core/types/unit: V
+
+fun sumdowntour/sumdown: (sum : ? int) -> <div,state<int>> int( sumsum: ? int : intstd/core/types/int: V = 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
)result: -> <state<int>,div> int : <std/core/types/total: Estatetour/state: (V, E, V) -> V<intstd/core/types/int: V>,divstd/core/types/div: X> intstd/core/types/int: V + val ii: int = gettour/get: () -> <state<int>,div> int() + if ii: int <=std/core/int/(<=): (x : int, y : int) -> <div,state<int>> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
then sumsum: int else + settour/set: (x : int) -> <state<int>,div> ()( ii: int -std/core/int/(-): (x : int, y : int) -> <state<int>,div> int 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
) + sumdowntour/sumdown: (sum : ? int) -> <div,state<int>> int( sumsum: int +std/core/int/(+): (x : int, y : int) -> <div,state<int>> int ii: int
) +
+ + + +

We can define a generic state handler most easily by using var declarations: +

fun state( init : a, action : () -> <state<a>,div|e> b ) : <div|e> b
+  var st := init
+  with handler
+    fun get()  st
+    fun set(i) st := i
+  action()
+fun statetour/state: forall<a,b,e> (init : a, action : () -> <state<a>,div|e> b) -> <div|e> b( initinit: $8217 : aa: V, actionaction: () -> <state<$8217>,div|$8219> $8218 : () -> <statetour/state: (V, E, V) -> V<aa: V>,divstd/core/types/div: X|std/core/types/effect-extend: (X, E) -> Eee: E> bb: V )result: -> <div|8476> 8475 : <divstd/core/types/div: X|std/core/types/effect-extend: (X, E) -> Eee: E> bb: V
+  var stst: local-var<$8228,$8217> := initinit: $8217
+  withwith: () -> <state<$8217>,div|$8219> $8218 handlerhandler: (() -> <state<$8217>,local<$8228>,div|$8219> $8218) -> <local<$8228>,div|$8219> $8218
+    fun getget: () -> <local<$8228>,div|$8219> $8217()  stst: $8217
+    fun setset: (i : $8217) -> <local<$8228>,div|$8219> ()(ii: $8217) stst: local-var<$8228,$8217> :=std/core/types/local-set: (v : local-var<$8228,$8217>, assigned : $8217) -> <local<$8228>,div|$8219> () ii: $8217
+  actionaction: () -> <state<$8217>,div|$8219> $8218()
+
+ + + +

where statetour/state: forall<a,b,e> (init : a, action : () -> <state<a>,div|e> b) -> <div|e> b(10){ sumdowntour/sumdown: (sum : ? int) -> <div,state<int>> int() } evaluates to 55. +

+

Read more about default parameters

+

Read more about trailing lambdas

+

Read more about var mutable variables

+

Building on the previous state example, suppose we also like +to return the final state. A nice way to do this is to +use a return operation again to pair the final result with the final state: +

fun pstate( init : a, action : () -> <state<a>,div|e> b ) : <div|e> (b,a)
+  var st := init
+  with handler
+    return(x)  (x,st)       // pair with the final state
+    fun get()  st
+    fun set(i) st := i
+  action()
+fun pstatetour/pstate: forall<a,b,e> (init : a, action : () -> <state<a>,div|e> b) -> <div|e> (b, a)( initinit: $4934 : aa: V, actionaction: () -> <state<$4934>,div|$4936> $4935 : () -> <statetour/state: (V, E, V) -> V<aa: V>,divstd/core/types/div: X|std/core/types/effect-extend: (X, E) -> Eee: E> bb: V )result: -> <div|5269> (5268, 5267) : <divstd/core/types/div: X|std/core/types/effect-extend: (X, E) -> Eee: E> (std/core/types/tuple2: (V, V) -> Vbb: V,aa: V)
+  var stst: local-var<$4945,$4934> := initinit: $4934
+  withwith: () -> <state<$4934>,div|$4936> $4935 handlerhandler: (() -> <state<$4934>,local<$4945>,div|$4936> $4935) -> <local<$4945>,div|$4936> ($4935, $4934)
+    returnreturn: (x : _4963) -> <local<$4945>,div|_5251> (_4963, $4934)(xx: _4963)  (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)xx: _4963,stst: $4934)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)       // pair with the final state
+    fun getget: () -> <local<$4945>,div|$4936> $4934()  stst: $4934
+    fun setset: (i : $4934) -> <local<$4945>,div|$4936> ()(ii: $4934) stst: local-var<$4945,$4934> :=std/core/types/local-set: (v : local-var<$4945,$4934>, assigned : $4934) -> <local<$4945>,div|$4936> () ii: $4934
+  actionaction: () -> <state<$4934>,div|$4936> $4935()
+
+ + +

where pstatetour/pstate: forall<a,b,e> (init : a, action : () -> <state<a>,div|e> b) -> <div|e> (b, a)(10){ sumdowntour/sumdown: (sum : ? int) -> <div,state<int>> int() } evaluates to (55,0). +

+
+

advancedIt is even possible to have a handler that only +contains a single return operation: such handler handles no effect +at all but only transforms the final result of a function. +For example, we can define the previous example also with +a separate return handler as: +

fun pstate2( init : a, action : () -> <state<a>,div|e> b ) : <div|e> (b,a)
+  var st := init
+  with return(x) (x,st)
+  with handler
+    fun get()  st
+    fun set(i) st := i
+  action()
+fun pstate2tour/pstate2: forall<a,b,e> (init : a, action : () -> <state<a>,div|e> b) -> <div|e> (b, a)( initinit: $7656 : aa: V, actionaction: () -> <state<$7656>,div|$7658> $7657 : () -> <statetour/state: (V, E, V) -> V<aa: V>,divstd/core/types/div: X|std/core/types/effect-extend: (X, E) -> Eee: E> bb: V )result: -> <div|7953> (7952, 7951) : <divstd/core/types/div: X|std/core/types/effect-extend: (X, E) -> Eee: E> (std/core/types/tuple2: (V, V) -> Vbb: V,aa: V)
+  var stst: local-var<$7667,$7656> := initinit: $7656
+  withwith: () -> <local<$7667>,div|$7658> $7657 returnreturn: (x : $7657) -> <local<$7667>,div|$7658> ($7657, $7656)(xx: $7657) (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)xx: $7657,stst: $7656)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)
+  withwith: () -> <state<$7656>,div|$7658> $7657 handlerhandler: (() -> <state<$7656>,local<$7667>,div|$7658> $7657) -> <local<$7667>,div|$7658> $7657
+    fun getget: () -> <local<$7667>,div|$7658> $7656()  stst: $7656
+    fun setset: (i : $7656) -> <local<$7667>,div|$7658> ()(ii: $7656) stst: local-var<$7667,$7656> :=std/core/types/local-set: (v : local-var<$7667,$7656>, assigned : $7656) -> <local<$7667>,div|$7658> () ii: $7656
+  actionaction: () -> <state<$7656>,div|$7658> $7657()
+
+ + + +

Here it as a bit contrived but it can make certain +programs more concise in their definition, see +for example [5].

3.4.6. Combining Handlers

+
+

advancedWhat makes effect handlers a good control-flow abstraction? There are three fundamental advantages +with regard to other approaches: +

+
    +
  1. Effect handlers can have simple (Hindley-Milner) types. This unlike shift/reset for example as that needs +type rules with answer types (as the type of shift depends on the context of its matching reset). +
  2. +
  3. The scope of an effect handler is delimited by the handler definition. This is just like shift/reset +but unlike call/cc. Delimiting the scope of a resumption has various good properties, like efficient +implementation strategies, but also that it allows for modular composition +(see also Oleg Kiselyov's “against call/cc”). +
  4. +
  5. Effect handlers can be composed freely. This is unlike general monads which need monad transformers to +compose in particular ways. Essentially effect handlers can compose freely because every effect handler +can be expressed eventually as an instance of a free monad which do compose. This also means that +some monads cannot be expressed as an effect handler (namely the non-algebraic ones). A particular example +of this is the continuation monad (which can express call/cc). +
+ +

The Koka compiler internally uses monads and shift/reset to compile effect handlers though, and +it compiles handlers into to an internal free monad based on multi-prompt delimited control [4, 25]. +By inlining the monadic bind we are able to generate efficient C code that only allocates continuations +in the case one is actually yielding up to a general ctl operation.

+

A great property of effect handlers is that they can be freely composed together. +For example, suppose we have a function +that calls raisetour/raise: forall<a> (msg : string) -> raise a if the state is an odd number: +

fun no-odds() : <raise,state<int>> int
+  val i = get()
+  if i.is-odd then raise("no odds") else
+    set(i / 2)
+    i
+fun no-oddstour/no-odds: () -> <raise,state<int>> int()result: -> <raise,state<int>> int : <std/core/types/total: Eraisetour/raise: (E, V) -> V,statetour/state: (V, E, V) -> V<intstd/core/types/int: V>> intstd/core/types/int: V
+  val ii: int = gettour/get: () -> <state<int>,raise> int()
+  if ii: int.is-oddstd/core/int/is-odd: (i : int) -> <raise,state<int>> bool then raisetour/raise: (msg : string) -> <raise,state<int>> int("no odds"literal: string
count= 7
) else + settour/set: (x : int) -> <state<int>,raise> ()(ii: int /std/core/int/(/): (x : int, y : int) -> <state<int>,raise> int 2literal: int
dec = 2
hex8 = 0x02
bit8 = 0b00000010
) +
ii: int +
+ + + +

then we can compose a pstatetour/pstate: forall<a,b,e> (init : a, action : () -> <state<a>,div|e> b) -> <div|e> (b, a) and raise-maybetour/raise-maybe: forall<a,e> (action : () -> <raise|e> a) -> e maybe<a> handler together +to handle the effects: +

fun state-raise(init) : div (maybe<int>,int)
+  with pstate(init)
+  with raise-maybe
+  no-odds()
+fun state-raisetour/state-raise: (init : int) -> div (maybe<int>, int)(initinit: int)result: -> div (maybe<int>, int) : divstd/core/types/div: X (std/core/types/tuple2: (V, V) -> Vmaybestd/core/types/maybe: V -> V<intstd/core/types/int: V>,intstd/core/types/int: V)
+  withwith: () -> <state<int>,div> maybe<int> pstatetour/pstate: (init : int, action : () -> <state<int>,div> maybe<int>) -> div (maybe<int>, int)(initinit: int)
+  withwith: () -> <raise,state<int>,div> int raise-maybetour/raise-maybe: (action : () -> <raise,state<int>,div> int) -> <state<int>,div> maybe<int>
+  no-oddstour/no-odds: () -> <raise,state<int>,div> int()
+
+ + + +

where both the statetour/state: (V, E, V) -> V<intstd/core/types/int: V> and raisetour/raise: (E, V) -> V effects are discharged by the respective handlers. +Note the type reflects that we always return a pair with as a first element either +Nothingstd/core/types/Nothing: forall<a> maybe<a> (if raisetour/raise: forall<a> (msg : string) -> raise a was called) or a Juststd/core/types/Just: forall<a> (value : a) -> maybe<a> with the final result, and as the second element +the final state. This corresponds to how we usually combine state and exceptions where the +state (or heap) has set to the state at the point the exception happened. +

+

However, if we combine the handlers in the opposite order, we get a form of transactional +state where we either get an exception (and no final state), or we get a pair of the +result with the final state: +

fun raise-state(init) : div maybe<(int,int)>
+  with raise-maybe
+  with pstate(init)
+  no-odds()
+fun raise-statetour/raise-state: (init : int) -> div maybe<(int, int)>(initinit: int)result: -> div maybe<(int, int)> : divstd/core/types/div: X maybestd/core/types/maybe: V -> V<(std/core/types/tuple2: (V, V) -> Vintstd/core/types/int: V,intstd/core/types/int: V)>
+  withwith: () -> <raise,div> (int, int) raise-maybetour/raise-maybe: (action : () -> <raise,div> (int, int)) -> div maybe<(int, int)>
+  withwith: () -> <state<int>,div,raise> int pstatetour/pstate: (init : int, action : () -> <state<int>,div,raise> int) -> <div,raise> (int, int)(initinit: int)
+  no-oddstour/no-odds: () -> <raise,state<int>,div> int()
+
+ + +

3.4.7. Masking Effects

+

Similar to masking signals in Unix, we can mask effects to not be handled by +their innermost effect handler. The expression mask<eff>(action) modularly masks +any effect operations in eff inside the action. For example, +consider two nested handlers for the emittour/emit: (msg : string) -> emit () operation: +

fun mask-emit()
+  with fun emit(msg) println("outer:" ++ msg)
+  with fun emit(msg) println("inner:" ++ msg)
+  emit("hi")
+  mask<emit>
+    emit("there")
+fun mask-emittour/mask-emit: () -> console ()()result: -> console ()
+  withhandler: (() -> <emit,console> ()) -> console () fun emitemit: (msg : string) -> console ()(msgmsg: string) printlnstd/core/console/string/println: (s : string) -> console ()("outer:"literal: string
count= 6
++std/core/types/(++): (x : string, y : string) -> console string msgmsg: string) + withhandler: (() -> <emit,console,emit> ()) -> <console,emit> () fun emitemit: (msg : string) -> <console,emit> ()(msgmsg: string) printlnstd/core/console/string/println: (s : string) -> <console,emit> ()("inner:"literal: string
count= 6
++std/core/types/(++): (x : string, y : string) -> <console,emit> string msgmsg: string) + emittour/emit: (msg : string) -> <emit,emit,console> ()("hi"literal: string
count= 2
) + mask<emittour/emit: (E, V) -> V> + emittour/emit: (msg : string) -> <emit,console> ()("there"literal: string
count= 5
) +
+ + +

If we call mask-emittour/mask-emit: () -> console ()() it prints: +

+
inner: hi
+outer: there
+

The second call to emittour/emit: (msg : string) -> emit () is masked and therefore it skips the innermost +handler and is handled subsequently by the outer handler (i.e. mask only +masks an operation once for its innermost handler). +

+

The type of mask<l> for some effect label l is (action: () -> e a) -> <l|e> a +where it injects the effect l into the final effect result <l|e> (even +thought the mask itself never +actually performs any operation in l – it only masks any operations +of l in action). +

+

This type usually leads to duplicate effect labels, for example, +the effect of mask<emittour/emit: (msg : string) -> emit ()>{ emittour/emit: (msg : string) -> emit ()("there") } is <emittour/emit: (E, V) -> V,emittour/emit: (E, V) -> V> signifying +that there need to be two handlers for emittour/emit: (E, V) -> V: in this case, one to skip +over, and one to subsequently handle the masked operation. +

Effect Abstraction

+

The previous example is not very useful, but generally we can +use mask to hide internal effect handling from higher-order functions. +For example, consider the following function that needs to handle +internal exceptions: +

fun mask-print( action : () -> e int ) : e int
+  with ctl raise(msg) 42
+  val x = mask<raise>(action)
+  if x.is-odd then raise("wrong")   // internal exception
+  x
+fun mask-printtour/mask-print: forall<e> (action : () -> e int) -> e int( actionaction: () -> $7129 int : () -> ee: E intstd/core/types/int: V )result: -> 7224 int : ee: E intstd/core/types/int: V
+  withhandler: (() -> <raise|$7129> int) -> $7129 int ctl raiseraise: (msg : string, resume : (_7135) -> $7129 int) -> $7129 int
(msgmsg: string) 42literal: int
dec = 42
hex8 = 0x2A
bit8 = 0b00101010
+ val xx: int = mask<raisetour/raise: (E, V) -> V>(actionaction: () -> $7129 int) + if xx: int.is-oddstd/core/int/is-odd: (i : int) -> <raise|$7129> bool then raisetour/raise: (msg : string) -> <raise|$7129> ()("wrong"literal: string
count= 5
)std/core/types/Unit: () // internal exception +
xx: int +
+ + + +

Here the type of mask-printtour/mask-print: forall<e> (action : () -> e int) -> e int does not expose at all that we handle the raisetour/raise: (E, V) -> V +effect internally for specific code and it is fully abstract – even if the action itself would call raisetour/raise: forall<a> (msg : string) -> raise a, +it would neatly skip the internal handler due to the mask<raisetour/raise: forall<a> (msg : string) -> raise a> expression. +

+

If we would leave out the mask, and call action() directly, then the inferred +type of action would be () -> <raisetour/raise: (E, V) -> V|e> intstd/core/types/int: V instead, showing that the raisetour/raise: (E, V) -> V +effect would be handled. +Note that this is usually the desired behaviour since in the majority of cases +we want to handle the effects in a particular way when defining handler abstractions. +The cases where mask is needed are much less common in our experience. +

+
+

advanced +

State as a Combined Effect

+

Another nice use-case for mask occurs when modeling state directly using +effect handlers without using mutable local variables [1]. We can do this +using two separate operations peektour/peek: forall<a> -> (peek<a>) a and poketour/poke: forall<a> (x : a) -> (poke<a>) (): +

effect<a> val peek : a             // get the state
+effect<a> ctl poke( x : a ) : ()   // set the state to x
+effecttour/peek: (V, E, V) -> V<aa: V> val peektour/peek: (V, E, V) -> V : aa: V             // get the state
+effecttour/poke: (V, E, V) -> V<aa: V> ctl poketour/poke: (V, E, V) -> V( xx: $7269 : aa: V ) : (std/core/types/unit: V)std/core/types/unit: V   // set the state to x
+
+ + + +

We can now define a generic state handler as: +

fun ppstate( init : a, action : () -> <peek<a>,poke<a>|e> b ) : e b
+  with val peek = init
+  with ctl poke(x)
+    mask<peek>
+      with val peek = x
+      resume(())
+  action()
+fun ppstatetour/ppstate: forall<a,b,e> (init : a, action : () -> <peek<a>,poke<a>|e> b) -> e b( initinit: $7322 : aa: V, actionaction: () -> <peek<$7322>,poke<$7322>|$7324> $7323 : () -> <peektour/peek: (V, E, V) -> V<aa: V>,poketour/poke: (V, E, V) -> V<aa: V>|std/core/types/effect-extend: (X, E) -> Eee: E> bb: V )result: -> 7552 7551 : ee: E bb: V
+  withhandler: (() -> <peek<$7322>|$7324> $7323) -> $7324 $7323 val peekpeek: () -> $7324 $7322 = initinit: $7322
+  withhandler: (() -> <poke<$7322>,peek<$7322>|$7324> $7323) -> <peek<$7322>|$7324> $7323 ctl pokepoke: (x : $7322, resume : (()) -> <peek<$7322>|$7324> $7323) -> <peek<$7322>|$7324> $7323
(xx: $7322) + mask<peek_1: V> + withhandler: (() -> <peek<$7322>|$7324> $7323) -> $7324 $7323 val peekpeek: () -> $7324 $7322 = xx: $7322 + resumeresume: (()) -> <peek<$7322>|$7324> $7323((std/core/types/Unit: ())std/core/types/Unit: ()) + actionaction: () -> <peek<$7322>,poke<$7322>|$7324> $7323(
) +
+ + +

In the handler for poketour/poke: forall<a> (x : a) -> (poke<a>) () we resume under a fresh handler for peektour/peek: forall<a> -> (peek<a>) a that +is bound to the new state. This means though there will be an ever increasing +“stack” of handlers for peektour/peek: forall<a> -> (peek<a>) a. To keep the type from growing infinitely, we +need to mask out any potential operation to a previous handler of peektour/peek: forall<a> -> (peek<a>) a which +is why the mask is needed. (Another way of looking at this is to just follow +the typing: action has a peektour/peek: (V, E, V) -> V effect, and unifies with the effect of +the poketour/poke: forall<a> (x : a) -> (poke<a>) () operation definition. Since it handles its own peektour/peek: (V, E, V) -> V effect, it needs +to be injected back in with a mask.) +

+

(Note: since the handler stack grows indefinitely on every poketour/poke: forall<a> (x : a) -> (poke<a>) () this example +is mostly of theoretical interest. However, we are looking into a stack smashing +technique where we detect at runtime that a mask can discard a handler frame +from the stack.) +

3.4.8. Overriding Handlers

+

A common use for masking is to override handlers. For example, consider +overriding the behavour of emittour/emit: (msg : string) -> emit (): +

fun emit-quoted1( action : () -> <emit,emit|e> a ) : <emit|e> a
+  with fun emit(msg) emit("\"" ++ msg ++ "\"")
+  action()
+fun emit-quoted1tour/emit-quoted1: forall<a,e> (action : () -> <emit,emit|e> a) -> <emit|e> a( actionaction: () -> <emit,emit|$6260> $6259 : () -> <emittour/emit: (E, V) -> V,emittour/emit: (E, V) -> V|std/core/types/effect-extend: (X, E) -> Eee: E> aa: V )result: -> <emit|6352> 6351 : <emittour/emit: (E, V) -> V|std/core/types/effect-extend: (X, E) -> Eee: E> aa: V
+  withhandler: (() -> <emit,emit|$6260> $6259) -> <emit|$6260> $6259 fun emitemit: (msg : string) -> <emit|$6260> ()(msgmsg: string) emittour/emit: (msg : string) -> <emit|$6260> ()("\""literal: string
count= 1
++std/core/types/(++): (x : string, y : string) -> <emit|$6260> string msgmsg: string ++std/core/types/(++): (x : string, y : string) -> <emit|$6260> string "\""literal: string
count= 1
) + actionaction: () -> <emit,emit|$6260> $6259(
) +
+ + + +

Here, the handler for emittour/emit: (msg : string) -> emit () calls itself emittour/emit: (msg : string) -> emit () to actually emit the newly +quoted string. The effect type inferred for emit-quoted1tour/emit-quoted1: forall<a,e> (action : () -> <emit,emit|e> a) -> <emit|e> a is (action : () -> <emittour/emit: (E, V) -> V,emittour/emit: (E, V) -> V|e> a) -> <emittour/emit: (E, V) -> V|e> a. +This is not the nicest type as it exposes that action is evaluated under (at least) two +emittour/emit: (E, V) -> V handlers (and someone could use mask inside action to use the outer emittour/emit: (E, V) -> V handler). +

+

The override keyword keeps the type nice and fully overrides the +previous handler which is no longer accessible from action: +

fun emit-quoted2( action : () -> <emit|e> a ) : <emit|e> a
+  with override fun emit(msg) emit("\"" ++ msg ++ "\"" )
+  action()
+fun emit-quoted2tour/emit-quoted2: forall<a,e> (action : () -> <emit|e> a) -> <emit|e> a( actionaction: () -> <emit|$6360> $6359 : () -> <emittour/emit: (E, V) -> V|std/core/types/effect-extend: (X, E) -> Eee: E> aa: V )result: -> <emit|6466> 6465 : <emittour/emit: (E, V) -> V|std/core/types/effect-extend: (X, E) -> Eee: E> aa: V
+  withhandler: (() -> <emit,emit|$6360> $6359) -> <emit|$6360> $6359 override fun emitemit: (msg : string) -> <emit|$6360> ()(msgmsg: string) emittour/emit: (msg : string) -> <emit|$6360> ()("\""literal: string
count= 1
++std/core/types/(++): (x : string, y : string) -> <emit|$6360> string msgmsg: string ++std/core/types/(++): (x : string, y : string) -> <emit|$6360> string "\""literal: string
count= 1
) + actionaction: () -> <emit|$6360> $6359(
) +
+ + + +

This of course applies to any handler or value, for example, +to temporarily increase the widthtour/width: -> width int while pretty printing, +we can override the widthtour/width: -> width int as: +

fun extra-wide( action )
+  with override val width = 2*width
+  action()
+fun extra-widetour/extra-wide: forall<a,e> (action : () -> <width|e> a) -> <width|e> a( actionaction: () -> <width|_6488> _6475 )result: -> <width|14053> 14040
+  withhandler: (() -> <width,width|_6488> _6475) -> <width|_6488> _6475 override val widthwidth: () -> <width|_6488> int = 2literal: int
dec = 2
hex8 = 0x02
bit8 = 0b00000010
*std/core/int/(*): (int, int) -> <width|_6488> intwidthtour/width: -> width int + actionaction: () -> <width|_6488> _6475(
) +
+ + + + +
+

advanced +

Mask Behind

+

Unfortunately, we cannot modularly define overriding with just mask; if we +add mask outside of the emittour/emit: (msg : string) -> emit () handler, the emittour/emit: (msg : string) -> emit () call inside the operation +definition would get masked and skip our intended handler. On the other hand, +if we add mask just over action all its emittour/emit: (msg : string) -> emit () calls would be masked for +our intended handler! +

+

For this situation, there is another primitive that only “masks the masks”. +The expression mask behind<eff> has type (() -> <eff|e> a) -> <eff,eff|e> a +and only masks any masked operations but not the direct ones. The override +keyword is defined in terms of this primitive: +

+
+

translation

+
with override handler<eff> { <ops> }
+<body>
+with override handler<eff> { <ops> }
+<body>
+
+ + +

$\mathpre{\rightsquigarrow}$ +

(handler<eff> { <ops> })(mask behind<eff>{ <body> })
+(handler<eff> { <ops> })(mask behind<eff>{ <body> })
+
+
+

This ensures any operation calls in <body> go the newly defined +handler while any masked operations are masked one more level and skip +both of the two innermost handlers.

3.4.9. Side-effect Isolation

3.4.10. Resuming more than once

+

Since resumestd/core/hnd/resume: forall<a,e,e1,b> (r : resume-context<a,e,e1,b>, x : a) -> e b is a first-class function (well, almost, see raw control), +it is possible to store it in a list for example to implement a scheduler, +but it is also possible to invoke it more than once. This can be used to +implement backtracking or probabilistic programming models. +

+

A common example of multiple resumptions is the choicetour/choice: (E, V) -> V effect: +

effect ctl choice() : bool
+
+fun xor() : choice bool
+  val p = choice()
+  val q = choice()
+  if p then !q else q
+effecttour/choice: (E, V) -> V ctl choicetour/choice: (E, V) -> V() : boolstd/core/types/bool: V
+
+fun xortour/xor: () -> choice bool()result: -> choice bool : choicetour/choice: (E, V) -> V boolstd/core/types/bool: V
+  val pp: bool = choicetour/choice: () -> choice bool()
+  val qq: bool = choicetour/choice: () -> choice bool()
+  if pp: bool then !std/core/types/bool/(!): (b : bool) -> choice boolqq: bool else qq: bool
+
+ + + +

One possible implementation just uses random numbers: +

fun choice-random(action : () -> <choice,random|e> a) : <random|e> a
+  with fun choice() random-bool()
+  action()
+fun choice-randomtour/choice-random: forall<a,e> (action : () -> <choice,random|e> a) -> <random|e> a(actionaction: () -> <choice,random|$4761> $4760 : () -> <choicetour/choice: (E, V) -> V,randomstd/num/random/random: (E, V) -> V|std/core/types/effect-extend: (X, E) -> Eee: E> aa: V)result: -> <random|4825> 4824 : <randomstd/num/random/random: (E, V) -> V|std/core/types/effect-extend: (X, E) -> Eee: E> aa: V
+  withhandler: (() -> <choice,random|$4761> $4760) -> <random|$4761> $4760 fun choicechoice: () -> <random|$4761> bool() random-boolstd/num/random/random-bool: () -> <random|$4761> bool()
+  actionaction: () -> <choice,random|$4761> $4760()
+
+ + + +

Where choice-randomtour/choice-random: forall<a,e> (action : () -> <choice,random|e> a) -> <random|e> a(xortour/xor: () -> choice bool) returns Truestd/core/types/True: bool and Falsestd/core/types/False: bool at random. +

+

However, we can also resume multiple times, once with Falsestd/core/types/False: bool and once with Truestd/core/types/True: bool, +to return all possible outcomes. This also changes the handler type to return a list +of all results of the action, and we need a return clause to wrap the result +of the action in a singleton list: +

fun choice-all(action : () -> <choice|e> a) : e list<a>
+  with handler
+    return(x)    [x]
+    ctl choice() resume(False) ++ resume(True)
+  action()
+fun choice-alltour/choice-all: forall<a,e> (action : () -> <choice|e> a) -> e list<a>(actionaction: () -> <choice|$4654> $4653 : () -> <choicetour/choice: (E, V) -> V|std/core/types/effect-extend: (X, E) -> Eee: E> aa: V)result: -> 4753 list<4752> : ee: E liststd/core/types/list: V -> V<aa: V>
+  withwith: () -> <choice|$4654> $4653 handlerhandler: (() -> <choice|$4654> $4653) -> $4654 list<$4653>
+    returnreturn: (x : $4653) -> _4657 list<$4653>(xx: $4653)    [std/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>xx: $4653]std/core/types/Nil: forall<a> list<a>
+    ctl choicechoice: (resume : (bool) -> $4654 list<$4653>) -> $4654 list<$4653>
() resumeresume: (bool) -> $4654 list<$4653>(Falsestd/core/types/False: bool) ++std/core/list/(++): (xs : list<$4653>, ys : list<$4653>) -> $4654 list<$4653> resumeresume: (bool) -> $4654 list<$4653>(Truestd/core/types/True: bool) + actionaction: () -> <choice|$4654> $4653(
) +
+ + +

where choice-alltour/choice-all: forall<a,e> (action : () -> <choice|e> a) -> e list<a>(xortour/xor: () -> choice bool) returns [Falsestd/core/types/False: bool,Truestd/core/types/True: bool,Truestd/core/types/True: bool,Falsestd/core/types/False: bool]. +

+

Resuming more than once interacts in interesting ways with the +state effect. Consider the following example that uses both +choicetour/choice: (E, V) -> V and statetour/state: (V, E, V) -> V: +

fun surprising() : <choice,state<int>> bool
+  val p = choice()
+  val i = get()
+  set(i+1)
+  if i>0 && p then xor() else False
+fun surprisingtour/surprising: () -> <choice,state<int>> bool()result: -> <choice,state<int>> bool : <std/core/types/total: Echoicetour/choice: (E, V) -> V,statetour/state: (V, E, V) -> V<intstd/core/types/int: V>> boolstd/core/types/bool: V
+  val pp: bool = choicetour/choice: () -> <choice,state<int>> bool()
+  val ii: int = gettour/get: () -> <state<int>,choice> int()
+  settour/set: (x : int) -> <state<int>,choice> ()(ii: int+std/core/int/(+): (x : int, y : int) -> <state<int>,choice> int1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
) + if ii: int>std/core/int/(>): (x : int, y : int) -> <choice,state<int>> bool0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
&&std/core/types/(&&): (x : bool, y : bool) -> <choice,state<int>> bool pp: bool then xortour/xor: () -> <choice,state<int>> bool() else Falsestd/core/types/False: bool
+
+ + + +

We can combine the handlers in two interesting ways: +

fun state-choice() : div (list<bool>,int)
+  pstate(0)
+    choice-all(surprising)
+
+fun choice-state() : div list<(bool,int)>
+  choice-all
+    pstate(0,surprising)
+fun state-choicetour/state-choice: () -> div (list<bool>, int)()result: -> div (list<bool>, int) : divstd/core/types/div: X (std/core/types/tuple2: (V, V) -> Vliststd/core/types/list: V -> V<boolstd/core/types/bool: V>,intstd/core/types/int: V)
+  pstatetour/pstate: (init : int, action : () -> <state<int>,div> list<bool>) -> div (list<bool>, int)(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) + choice-alltour/choice-all: (action : () -> <choice,state<int>,div> bool) -> <state<int>,div> list<bool>(surprisingtour/surprising: () -> <choice,state<int>,div> bool
) + +fun choice-statetour/choice-state: () -> div list<(bool, int)>()result: -> div list<(bool, int)> : divstd/core/types/div: X liststd/core/types/list: V -> V<(std/core/types/tuple2: (V, V) -> Vboolstd/core/types/bool: V,intstd/core/types/int: V)> + choice-alltour/choice-all: (action : () -> <choice,div> (bool, int)) -> div list<(bool, int)> + pstatetour/pstate: (init : int, action : () -> <state<int>,div,choice> bool) -> <div,choice> (bool, int)(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
,surprisingtour/surprising: () -> <choice,state<int>,div> bool
) +
+ + + +

In state-choicetour/state-choice: () -> div (list<bool>, int)() the pstatetour/pstate: forall<a,b,e> (init : a, action : () -> <state<a>,div|e> b) -> <div|e> (b, a) is the outer handler and becomes like a global +state over all resumption strands in choice-alltour/choice-all: forall<a,e> (action : () -> <choice|e> a) -> e list<a>, and thus after the first resume +the i>0 (&&)std/core/types/(&&): (x : bool, y : bool) -> bool p condition in surprisingtour/surprising: () -> <choice,state<int>> bool is Truestd/core/types/True: bool, and we get ([Falsestd/core/types/False: bool,Falsestd/core/types/False: bool,Truestd/core/types/True: bool,Truestd/core/types/True: bool,Falsestd/core/types/False: bool],2). +

+

In choice-statetour/choice-state: () -> div list<(bool, int)>() the pstatetour/pstate: forall<a,b,e> (init : a, action : () -> <state<a>,div|e> b) -> <div|e> (b, a) is the inner handler and becomes like transactional state, +where the state becomes local to each resumption strand in choice-alltour/choice-all: forall<a,e> (action : () -> <choice|e> a) -> e list<a>. +Now i is always 0 at first and thus we get [(Falsestd/core/types/False: bool,1),(Falsestd/core/types/False: bool,1)]. +

+
+

advancedThis example also shows how var state is correctly saved and restored on resumptions +(as part of the stack) and this is essential to the correct composition of effect handlers. +If var declarations were instead heap allocated or captured by reference, they would no +longer be local to their scope and side effects could “leak” across different resumptions.

3.4.11. Initially and Finally

+

With arbitrary effect handlers we need to be careful when interacting with external +resources like files. Generally, operations can never resume (like exceptions), +resume exactly once (giving the usual linear control flow), or resume more than once. +To robustly handle these different cases, Koka provides the finallystd/core/hnd/finally: forall<a,e> (fin : () -> e (), action : () -> e a) -> e a and initiallystd/core/hnd/initially: forall<a,e> (init : (int) -> e (), action : () -> e a) -> e a +functions. Suppose we have the following low-level file operations on file handles: +

type fhandle
+fun fopen( path : string )   : <exn,filesys> fhandle
+fun hreadline( h : fhandle ) : <exn,filesys> string
+fun hclose( h : fhandle )    : <exn,filesys> ()
+type fhandle
+fun fopen( path : stringstd/core/types/string: V )   : <exnstd/core/exn/exn: (E, V) -> V,filesys> fhandle
+fun hreadline( h : fhandle ) : <exnstd/core/exn/exn: (E, V) -> V,filesys> stringstd/core/types/string: V
+fun hclose( h : fhandle )    : <exnstd/core/exn/exn: (E, V) -> V,filesys> ()
+
+ + + +

Using these primitives, we can declare a fread effect to read from a file: +

effect fun fread() : string
+
+fun with-file( path : string, action : () -> <fread,exn,filesys|e> a ) : <exn,filesys|e> a
+  val h = fopen(path)
+  with handler
+    return(x)   { hclose(h); x }
+    fun fread() hreadline(h)
+  action()
+effect fun fread() : stringstd/core/types/string: V
+
+fun with-file( path : stringstd/core/types/string: V, action : () -> <fread,exnstd/core/exn/exn: (E, V) -> V,filesys|e> a ) : <exnstd/core/exn/exn: (E, V) -> V,filesys|e> a
+  val h = fopen(path)
+  with handler
+    return(x)   { hclose(h); x }
+    fun fread() hreadline(h)
+  action()
+
+ + + +

However, as it stands it would fail to close the file handle if an exceptional +effect inside action is used (i.e. or any operation that never resumes). +The finallystd/core/hnd/finally: forall<a,e> (fin : () -> e (), action : () -> e a) -> e a function handles these situations, and +takes as its first argument a function that is always executed when either returning normally, or +when unwinding for a non-resuming operation. So, a more robust way to write +with-file is: +

fun with-file( path : string, action : () -> <fread,exn,filesys|e> a ) : <exn,filesys|e> a
+  val h = fopen(path)
+  with finally
+    hclose(h)
+  with fun fread()
+    hreadline(h)
+  action()
+fun with-file( path : stringstd/core/types/string: V, action : () -> <fread,exnstd/core/exn/exn: (E, V) -> V,filesys|e> a ) : <exnstd/core/exn/exn: (E, V) -> V,filesys|e> a
+  val h = fopen(path)
+  with finallystd/core/hnd/finally: forall<a,e> (fin : () -> e (), action : () -> e a) -> e a
+    hclose(h)
+  with fun fread()
+    hreadline(h)
+  action()
+
+ + + +

The current definition is robust for operations that never resume, or operations that resume once +– but there is still trouble when resuming more than once. If someone calls choicetour/choice: () -> choice bool inside +the action, the second time it +resumes the file handle will be closed again which is probably not intended. There is +active research into using the type system to statically prevent this from happening. +

+

Another way to work with multiple resumptions is to use the initiallystd/core/hnd/initially: forall<a,e> (init : (int) -> e (), action : () -> e a) -> e a function. +This function takes 2 arguments: the first argument is a function that is called +the first time initiallystd/core/hnd/initially: forall<a,e> (init : (int) -> e (), action : () -> e a) -> e a is evaluated, and subsequently every time a particular resumption is +resumed more than once. +

+ + + + +

Raw Control

+
+

advancedUse raw ctl for raw control operations which do not automatically +finalize. With raw ctl one can use the implicitly bound +resumption context rcontext to either resume (as rcontext.resumestd/core/hnd/resume: forall<a,e,e1,b> (r : resume-context<a,e,e1,b>, x : a) -> e b(x)), +or to finalize a resumption (as rcontext.finalizestd/core/hnd/finalize: forall<a,e,e1,b> (r : resume-context<a,e,e1,b>, x : b) -> e b) which runs all +finallystd/core/hnd/finally: forall<a,e> (fin : () -> e (), action : () -> e a) -> e a handlers to clean up resources. This allows one to store an rcontext +as a first class value to resume or finalize later even from a different +scope. Of course, it needs to be used with care since it is now the +programmers' resposibility to ensure the resumption is eventually resumed +or finalized (such that any resources can be released).

3.4.12. Linear Effects

+
+

Todo. +Use linear effect to declare effects whose operations are always tail-resumptive +and use only linear effects themselves +(and thus resume exactly once). This removes monadic translation for such effects and +can make code that uses only linear effects more compact and efficient.

3.4.13. Named and Scoped Handlers

+
+

Todo. +See named-handlers.

3.5. FBIP: Functional but In-Place

+

With Perceus reuse analysis we can +write algorithms that dynamically adapt to use in-place mutation when +possible (and use copying when used persistently). Importantly, +you can rely on this optimization happening, e.g. see +the match patterns and pair them to same-sized constructors in each branch. +

+

This style of programming leads to a new paradigm that we call FBIP: +“functional but in place”. Just like tail-call optimization lets us +describe loops in terms of regular function calls, reuse analysis lets us +describe in-place mutating imperative algorithms in a purely functional +way (and get persistence as well). +

+
+

Note. +FBIP is still active research. In particular we'd like to add ways to add +annotations to ensure reuse is taking place.

3.5.1. Tree Rebalancing

+

As an example, we consider +insertion into a red-black tree [3]. +A polymorphic version of this example is part of the samples directory when you have +installed Koka and can be loaded as :l samples/basic/rbtree. +We define red-black trees as: +

type color
+  Red
+  Black
+
+type tree
+  Leaf
+  Node(color: color, left: tree, key: int, value: bool, right: tree)
+type color
+  Red
+  Black
+
+type treetour/tree: V
+  Leaf
+  Node(color: color, left: treetour/tree: V, key: intstd/core/types/int: V, value: boolstd/core/types/bool: V, right: treetour/tree: V)
+
+ + +

The red-black tree has the invariant that the number of black nodes from +the root to any of the leaves is the same, and that a red node is never a +parent of red node. Together this ensures that the trees are always +balanced. When inserting nodes, the invariants need to be maintained by +rebalancing the nodes when needed. Okasaki's algorithm [19] +implements this elegantly and functionally: +

fun balance-left( l : tree, k : int, v : bool, r : tree ): tree
+  match l
+    Node(_, Node(Red, lx, kx, vx, rx), ky, vy, ry)
+      -> Node(Red, Node(Black, lx, kx, vx, rx), ky, vy, Node(Black, ry, k, v, r))
+    ...
+
+fun ins( t : tree, k : int, v : bool ): tree
+  match t
+    Leaf -> Node(Red, Leaf, k, v, Leaf)
+    Node(Red, l, kx, vx, r)
+      -> if k < kx then Node(Red, ins(l, k, v), kx, vx, r)
+         ...
+    Node(Black, l, kx, vx, r)
+      -> if k < kx && is-red(l) then balance-left(ins(l,k,v), kx, vx, r)
+         ...
+fun balance-left( l : treetour/tree: V, k : intstd/core/types/int: V, v : boolstd/core/types/bool: V, r : treetour/tree: V ): treetour/tree: V
+  match l
+    Node(_, Node(Red, lx, kx, vx, rx), ky, vy, ry)
+      -> Node(Red, Node(Black, lx, kx, vx, rx), ky, vy, Node(Black, ry, k, v, r))
+    ...
+
+fun ins( t : treetour/tree: V, k : intstd/core/types/int: V, v : boolstd/core/types/bool: V ): treetour/tree: V
+  match t
+    Leaf -> Node(Red, Leaf, k, v, Leaf)
+    Node(Red, l, kx, vx, r)
+      -> if k < kx then Node(Red, ins(l, k, v), kx, vx, r)
+         ...
+    Node(Black, l, kx, vx, r)
+      -> if k < kx (&&)std/core/types/(&&): (x : bool, y : bool) -> bool is-red(l) then balance-left(ins(l,k,v), kx, vx, r)
+         ...
+
+ + + +

The Koka compiler will inline the balance-left function. At that point, +every matched Node constructor in the ins function has a corresponding Node allocation – +if we consider all branches we can see that we either match one Node +and allocate one, or we match three nodes deep and allocate three. Every +Node is actually reused in the fast path without doing any allocations! +When studying the generated code, we can see the Perceus assigns the +fields in the nodes in the fast path in-place much like the +usual non-persistent rebalancing algorithm in C would do. +

+

Essentially this means that for a unique tree, the purely functional +algorithm above adapts at runtime to an in-place mutating re-balancing +algorithm (without any further allocation). Moreover, if we use the tree +persistently [20], and the tree is shared or has +shared parts, the algorithm adapts to copying exactly the shared spine +of the tree (and no more), while still rebalancing in place for any +unshared parts. +

3.5.2. Morris Traversal

+

As another example of FBIP, consider mapping a function f over +all elements in a binary tree in-order as shown in the tmap-inordertour/tmap-inorder: (t : tree, f : (int) -> int) -> tree example: +

type tree
+  Tip
+  Bin( left: tree, value : int, right: tree )
+
+fun tmap-inorder( t : tree, f : int -> int ) : tree
+  match t
+    Bin(l,x,r) -> Bin( l.tmap-inorder(f), f(x), r.tmap-inorder(f) )
+    Tip        -> Tip
+type treetour/tree: V
+  Tiptour/Tip: tree
+  Bintour/Bin: (left : tree, value : int, right : tree) -> tree( left: treetour/tree: V, value : intstd/core/types/int: V, right: treetour/tree: V )
+
+fun tmap-inordertour/tmap-inorder: (t : tree, f : (int) -> int) -> tree( tt: tree : treetour/tree: V, ff: (int) -> int : intstd/core/types/int: V -> intstd/core/types/int: V )result: -> total tree : treetour/tree: V
+  match tt: tree
+    Bintour/Bin: (left : tree, value : int, right : tree) -> tree(ll: tree,xx: int,rr: tree) -> Bintour/Bin: (left : tree, value : int, right : tree) -> tree( ll: tree.tmap-inordertour/tmap-inorder: (t : tree, f : (int) -> int) -> tree(ff: (int) -> int), ff: (int) -> int(xx: int), rr: tree.tmap-inordertour/tmap-inorder: (t : tree, f : (int) -> int) -> tree(ff: (int) -> int) )
+    Tiptour/Tip: tree        -> Tiptour/Tip: tree
+
+ + + +

This is already quite efficient as all the Bintour/Bin: (left : tree, value : int, right : tree) -> tree and Tiptour/Tip: tree nodes are +reused in-place when t is unique. However, the tmaptour/tmap: (f : (int) -> int, t : tree, visit : visitor, d : direction) -> div tree function is not +tail-recursive and thus uses as much stack space as the depth of the +tree. +

+
void inorder( tree* root, void (*f)(tree* t) ) {
+  tree* cursor = root;
+  while (cursor != NULL /* Tip */) {
+    if (cursor->left == NULL) {
+      // no left tree, go down the right
+      f(cursor->value);
+      cursor = cursor->right;
+    } else {
+      // has a left tree
+      tree* pre = cursor->left;  // find the predecessor
+      while(pre->right != NULL && pre->right != cursor) {
+        pre = pre->right;
+      }
+      if (pre->right == NULL) {
+        // first visit, remember to visit right tree
+        pre->right = cursor;
+        cursor = cursor->left;
+      } else {
+        // already set, restore
+        f(cursor->value);
+        pre->right = NULL;
+        cursor = cursor->right;
+      }
+    }
+  }
+}
+

In 1968, Knuth posed the problem of visiting a tree in-order while using +no extra stack- or heap space [7] (For readers not familiar +with the problem it might be fun to try this in your favorite imperative +language first and see that it is not easy to do). Since then, numerous +solutions have appeared in the literature. A particularly elegant +solution was proposed by Morris [18]. This is an in-place mutating +algorithm that swaps pointers in the tree to “remember” which parts are +unvisited. It is beyond this tutorial to give a full explanation, but a C +implementation is shown here on the side. The traversal +essentially uses a right-threaded tree to keep track of which nodes to +visit. The algorithm is subtle, though. Since it transforms the tree into +an intermediate graph, we need to state invariants over the so-called +Morris loops [16] to prove its correctness. +

+

We can derive a functional and more intuitive solution using the FBIP +technique. We start by defining an explicit visitor data structure +that keeps track of which parts of the tree we still need to visit. In +Koka we define this data type as visitortour/visitor: V: +

type visitor
+  Done
+  BinR( right:tree, value : int, visit : visitor )
+  BinL( left:tree, value : int, visit : visitor )
+type visitortour/visitor: V
+  Donetour/Done: visitor
+  BinRtour/BinR: (right : tree, value : int, visit : visitor) -> visitor( right:treetour/tree: V, value : intstd/core/types/int: V, visit : visitortour/visitor: V )
+  BinLtour/BinL: (left : tree, value : int, visit : visitor) -> visitor( left:treetour/tree: V, value : intstd/core/types/int: V, visit : visitortour/visitor: V )
+
+ + + +

(As an aside, +Conor McBride [17] describes how we can +generically derive a zipper [6] visitor for any +recursive type $\mathpre{\mu \mathid{x}.~\mathid{F}}$ as a list of the derivative of that type, +namely $\mathpre{\mathkw{list}~(\pdv{\mathid{x}}~\mathid{F}\mid_{\mathid{x}~=\mu \mathid{x}.\mathid{F}})}$. +In our case, the algebraic representation of the inductive treetour/tree: V +type is $\mathpre{\mu \mathid{x}.~1~+~\mathid{x}\times \mathid{int}\times \mathid{x}~~\,\cong\,~\mu \mathid{x}.~1~+~\mathid{x}^2\times \mathid{int}}$. +Calculating the derivative $\mathpre{\mathkw{list}~(\pdv{\mathid{x}}~(1~+~\mathid{x}^2\times \mathid{int})~\mid_{\mathid{x}~=~\mathid{tree}})}$ +and by further simplification, +we get $\mathpre{\mu \mathid{x}.~1~+~(\mathid{tree}\times \mathid{int}\times \mathid{x})~+~(\mathid{tree}\times \mathid{int}\times \mathid{x})}$, +which corresponds exactly to our visitortour/visitor: V data type.) +

+

We also keep track of which directiontour/direction: V in the tree +we are going, either Uptour/Up: direction or Downtour/Down: direction the tree. +

type direction
+  Up
+  Down
+type directiontour/direction: V
+  Uptour/Up: direction
+  Downtour/Down: direction
+
+ + + +

We start our traversal by going downward into the tree with an empty +visitor, expressed as tmaptour/tmap: (f : (int) -> int, t : tree, visit : visitor, d : direction) -> div tree(f, t, Donetour/Done: visitor, Downtour/Down: direction): +

fun tmap( f : int -> int, t : tree, visit : visitor, d : direction )
+  match d
+    Down -> match t     // going down a left spine
+      Bin(l,x,r) -> tmap(f,l,BinR(r,x,visit),Down) // A
+      Tip        -> tmap(f,Tip,visit,Up)           // B
+    Up -> match visit   // go up through the visitor
+      Done        -> t                             // C
+      BinR(r,x,v) -> tmap(f,r,BinL(t,f(x),v),Down) // D
+      BinL(l,x,v) -> tmap(f,Bin(l,x,t),v,Up)       // E
+fun tmaptour/tmap: (f : (int) -> int, t : tree, visit : visitor, d : direction) -> div tree( ff: (int) -> int : intstd/core/types/int: V -> intstd/core/types/int: V, tt: tree : treetour/tree: V, visitvisit: visitor : visitortour/visitor: V, dd: direction : directiontour/direction: V )result: -> div tree
+  match dd: direction
+    Downtour/Down: direction -> match tt: tree     // going down a left spine
+      Bintour/Bin: (left : tree, value : int, right : tree) -> tree(ll: tree,xx: int,rr: tree) -> tmaptour/tmap: (f : (int) -> int, t : tree, visit : visitor, d : direction) -> div tree(ff: (int) -> int,ll: tree,BinRtour/BinR: (right : tree, value : int, visit : visitor) -> visitor(rr: tree,xx: int,visitvisit: visitor),Downtour/Down: direction) // A
+      Tiptour/Tip: tree        -> tmaptour/tmap: (f : (int) -> int, t : tree, visit : visitor, d : direction) -> div tree(ff: (int) -> int,Tiptour/Tip: tree,visitvisit: visitor,Uptour/Up: direction)           // B
+    Uptour/Up: direction -> match visitvisit: visitor   // go up through the visitor
+      Donetour/Done: visitor        -> tt: tree                             // C
+      BinRtour/BinR: (right : tree, value : int, visit : visitor) -> visitor(rr: tree,xx: int,vv: visitor) -> tmaptour/tmap: (f : (int) -> int, t : tree, visit : visitor, d : direction) -> div tree(ff: (int) -> int,rr: tree,BinLtour/BinL: (left : tree, value : int, visit : visitor) -> visitor(tt: tree,ff: (int) -> div int(xx: int),vv: visitor),Downtour/Down: direction) // D
+      BinLtour/BinL: (left : tree, value : int, visit : visitor) -> visitor(ll: tree,xx: int,vv: visitor) -> tmaptour/tmap: (f : (int) -> int, t : tree, visit : visitor, d : direction) -> div tree(ff: (int) -> int,Bintour/Bin: (left : tree, value : int, right : tree) -> tree(ll: tree,xx: int,tt: tree),vv: visitor,Uptour/Up: direction)       // E
+
+ + + +

The key idea is that we +are either Donetour/Done: visitor (C), or, on going downward in a left spine we +remember all the right trees we still need to visit in a BinRtour/BinR: (right : tree, value : int, visit : visitor) -> visitor (A) or, +going upward again (B), we remember the left tree that we just +constructed as a BinLtour/BinL: (left : tree, value : int, visit : visitor) -> visitor while visiting right trees (D). When we come +back up (E), we restore the original tree with the result values. Note +that we apply the function f to the saved value in branch D (as we +visit in-order), but the functional implementation makes it easy to +specify a pre-order traversal by applying f in branch A, or a +post-order traversal by applying f in branch E. +

+

Looking at each branch we can see that each Bintour/Bin: (left : tree, value : int, right : tree) -> tree matches up with a +BinRtour/BinR: (right : tree, value : int, visit : visitor) -> visitor, each BinRtour/BinR: (right : tree, value : int, visit : visitor) -> visitor with a BinLtour/BinL: (left : tree, value : int, visit : visitor) -> visitor, and finally each BinLtour/BinL: (left : tree, value : int, visit : visitor) -> visitor with a Bintour/Bin: (left : tree, value : int, right : tree) -> tree. +Since they all have the same size, if the tree is unique, each branch +updates the tree nodes in-place at runtime without any allocation, +where the visitortour/visitor: V structure is effectively overlaid over the tree +nodes while traversing the tree. Since all tmaptour/tmap: (f : (int) -> int, t : tree, visit : visitor, d : direction) -> div tree calls are tail calls, +this also compiles to a tight loop and thus needs no extra stack- or heap +space. +

+

Finally, just like with re-balancing tree insertion, the algorithm as +specified is still purely functional: it uses in-place updating when a +unique tree is passed, but it also adapts gracefully to the persistent +case where the input tree is shared, or where parts of the input tree are +shared, making a single copy of those parts of the tree. +

+

Read the Perceus technical report

4. Koka language specification

+

This is the draft language specification of the Koka language, version v3.1.1
+Currently only the lexical and context-free grammar are specified. +The standard libraries are documented separately. +

4.1. Lexical syntax

+

We define the grammar and lexical syntax of the language using standard BNF +notation where non-terminals are generated by alternative patterns: +

+
nonterm ::= pattern1 | pattern2
+

In the patterns, we use the following notations: +

+ + + + + + + + + + + +
terminal A terminal symbol (in ASCII)
x1B A character with hexadecimal code 1B
A..F The characters from “A” to “F” (using ASCII, i.e. x61..x66)
 
( pattern ) Grouping
[ pattern ] Optional occurrence of pattern
{ pattern } Zero or more occurrences of pattern
{ pattern }n Exactly n occurrences of pattern
pattern1 | pattern2 Choice: either pattern1 or pattern2
 
pattern<!diff> Difference: elements generated by pattern except those in diff
nonterm[lex] Generate nonterm by drawing lexemes from lex
+

Care must be taken to distinguish meta-syntax such as | and ) +from concrete terminal symbols as | and ). In the specification +the order of the productions is not important and at each point the +longest matching lexeme is preferred. For example, even though +fun is a reserved word, the word functional is considered a +single identifier.

4.1.1. Source code

+

Source code consists of a sequence of unicode characters. Valid characters in +actual program code consist strictly of ASCII characters which range from 0 to 127. +Only comments, string literals, and character literals are allowed to +contain extended unicode characters. The grammar is designed such that a lexical +analyzer and parser can directly work on UTF-8 encoded source files without +actually doing UTF-8 decoding or unicode category identification. +

4.2. Lexical grammar

+

In the specification of the lexical grammar all white space is explicit +and there is no implicit white space between juxtaposed symbols. The +lexical token stream is generated by the non-terminal lex which +consists of lexemes and whitespace. +

+

Before doing lexical analysis, there is a linefeed character inserted +at the start and end of the input, which makes it easier to specify line +comments and directives. +

4.2.1. Lexical tokens

+ + + + + + +
lex ::= lexeme | whitespace
lexeme   ::= conid | qconid
| varid | qvarid
| op | opid | qopid | wildcard
| integer | float | stringlit | charlit
| reserved | opreserved
| special
+

The main program consists of whitespace or lexeme's. The context-free +grammar will draw it's lexemes from the lex production. +

4.2.2. Identifiers

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
anyid ::= varid | qvarid | opid | qopid | conid | qconid
 
qconid ::= modulepath conid
qvarid ::= modulepath lowerid
modulepath ::= lowerid (/)std/core/int/(/): (x : int, y : int) -> int { lowerid (/)std/core/int/(/): (x : int, y : int) -> int }
 
conid ::= upperid
varid ::= lowerid<!reserved>
 
lowerid ::= lower idtail
upperid ::= upper idtail
wildcard ::= _ idtail
typevarid ::= letter { digit }
 
idtail ::= { idchar } [ idfinal ]
idchar ::= letter | digit | _ | -
idfinal ::= { ' }
 
reserved ::= infix | infixr | infixl
| module | import | as
| pub | abstract
| type | struct | alias | effect | con
| forall | exists | some
| fun | fn | val | var | extern
| if | then | else | elif
| match | return | with | in
| handle | handler | mask
| ctl | final | raw
| override | named
| interface | break | continue | unsafe (future reserved words)
 
specialid ::= co | rec | open | extendstd/core/sslice/extend: (slice : sslice, count : int) -> sslice | behind
| linear | value | reference
| inline | noinline | initiallystd/core/hnd/initially: forall<a,e> (init : (int) -> e (), action : () -> e a) -> e a | finallystd/core/hnd/finally: forall<a,e> (fin : () -> e (), action : () -> e a) -> e a
| js | c | cs | file
+

Identifiers always start with a letter, may contain underscores and +dashes, and can end with prime ticks. +Like in Haskell, constructors always begin with an uppercase +letter while regular identifiers are lowercase. The rationale is to +visibly distinguish constants from variables in pattern matches. +Here are some example of valid identifiers: +

x
+concat1
+visit-left
+is-nil
+x'
+Cons
+True  
+x
+concat1
+visit-left
+is-nilstd/core/types/is-nil: forall<a> (list : list<a>) -> bool
+x'
+Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>
+Truestd/core/types/True: bool  
+
+ + +

To avoid confusion with the subtraction operator, the occurrences of +dashes are restricted in identifiers. After lexical analysis, only +identifiers where each dash is surrounded on both sides with a letter +are accepted: +

+
fold-right
+n-1        // illegal, a digit cannot follow a dash
+n - 1      // n minus 1
+n-x-1      // illegal, a digit cannot follow a dash
+n-x - 1    // identifier "n-x" minus 1
+n - x - 1  // n minus x minus 1
+

Qualified identifiers are prefixed with a module path. Module +paths can be partial as long as they are unambiguous. +

+
core/map
+std/core/(&)

4.2.3. Operators and symbols

+ + + + + + + + + + + + + + + + +
qopid ::= modulepath opid
opid ::= ( symbols )
 
op ::= symbols<!opreserved | optype> | ||
 
symbols ::= symbol { symbol }| /
symbol ::= $ | (%)std/core/int/(%): (int, int) -> int | & | (*)std/core/int/(*): (int, int) -> int | +
| ~ | ! | \ | ()std/core/int/(): (i : int, exp : int) -> int | #
| = | . | : | - | ?
| anglebar
anglebar ::= < | > | |
 
opreserved ::= = | . | : | ->
optype ::= anglebar anglebar { anglebar }
 
special ::= { | } | ( | ) | [ | ] | | | ; | ,
 

4.2.4. Literals

+ + + + + + + + + + + + + + + + + + + + +
charlit ::= ' (char<!' | \> | escape) '
stringlit ::= " { char<!" | \> | escape } "
| r { # }n " rawcharsn " { # }n (n >= 0)
rawcharsn ::= { anychar }<!{ anychar } " { # }n { anychar }>
 
escape ::= \ ( charesc | hexesc )
charesc ::= n | r | t | \ | " | '
hexesc ::= x { hexdigit }2 | u { hexdigit }4 | U { hexdigit }6
 
float ::= [ - ] (decfloat | hexfloat)
decfloat ::= decimal (. digits [ decexp ] | decexp)
decexp ::= (e | E) exponent
hexfloat ::= hexadecimal (. hexdigits [ hexexp ] | hexexp)
hexexp ::= (p | P) exponent
exponent ::= [ - | + ] digit { digit }
 
integer ::= [ - ] (decimal | hexadecimal)
decimal ::= 0 | posdigit [ [ _ ] digits ]
hexadecimal ::= 0 (x | X) hexdigits
digits ::= digit { digit } { _ digit { digit } }
hexdigits ::= hexdigit { hexdigit } { _ hexdigit { hexdigit } }

4.2.5. White space

+ + + + + + + + + +
whitespace ::= white { white } | newline
white ::= space
| linecomment | blockcomment
| linedirective
 
linecomment ::= // { char | tab }
linedirective ::= newline # { char | tab }
 
blockcomment ::= /* blockpart { blockcomment blockpart } */ (allows nested comments)
blockpart ::= { anychar }<!{ anychar } (/*|*/{ anychar }>

4.2.6. Character classes

+ + + + + + + + + + + + + + + + + + + +
letter ::= upper | lower
upper ::= A..Z (i.e. x41..x5A)
lower ::= a..z (i.e. x61..x7A)
digit ::= 0..9 (i.e. x30..x39)
posdigit ::= 1..9
hexdigit ::= a..f | A..F | digit
 
anychar ::= char | tab | newline (in comments and raw strings)
newline ::= [ return ] linefeed (windows or unix style end of line)
 
space ::= x20 (a space)
tab ::= x09 (a tab (\t))
linefeed ::= x0A (a line feed (\n))
return ::= x0D (a carriage return (\r))
 
char ::= unicode<!control | surrogate | bidi> (includes space)
unicode ::= x00..x10FFFF
control ::= x00..x1F | x7F | x80..9F (C0, DEL, and C1)
surrogate ::= xD800..xDFFF
bidi ::= x200E | x200F | x202A..x202E | x2066..x2069 (bi-directional text control)
+

Actual program code consists only of 7-bit ASCII characters while only comments +and literals can contain extended unicode characters. As such, +a lexical analyzer can directly process UTF-8 encoded input as +a sequence of bytes without needing UTF-8 decoding or unicode character +classification1. +For security +[2], some character ranges are excluded: the C0 and C1 +control codes (except for space, +tab, carriage return, and line feeds), surrogate characters, and bi-directional +text control characters. +

4.3. Layout

+

Just like programming languages like +HaskellPythonJavaScriptScalaGo, etc., there is a layout rule +which automatically adds braces and semicolons at appropriate places: +

+ + +

The layout algorithm is performed on the token stream in-between lexing +and parsing, and is independent of both. In particular, there are no intricate +dependencies with the parser (which leads to very complex layout rules, as is the +case in languages like Haskell or JavaScript). +

+

Moreover, in contrast to purely token-based layout rules (as in Scala or Go for example), +the visual indentation in a Koka program corresponds directly to how the compiler +interprets the statements. Many tricky layout +examples in other programming languages are often based on a mismatch between +the visual representation and how a compiler interprets the tokens – with +Koka's layout rule such issues are largely avoided. +

+

Of course, it is still allowed to explicitly use semicolons and braces, +which can be used for example to put multiple statements on a single line: +

fun equal-line( x : int, y : int ) : io bool {
+  print("calculate equality"); (x == y)
+}  
+fun equal-linespec/equal-line: (x : int, y : int) -> io bool( xx: int : intstd/core/types/int: V, yy: int : intstd/core/types/int: V )result: -> io bool : iostd/core/io: E boolstd/core/types/bool: V {
+  printstd/core/console/string/print: (s : string) -> <console,alloc<global>,div,exn,fsys,ndet,net,read<global>,ui,write<global>> ()("calculate equality"literal: string
count= 18
); (xx: int ==std/core/int/(==): (x : int, y : int) -> <console,alloc<global>,div,exn,fsys,ndet,net,read<global>,ui,write<global>> bool yy: int) +
} +
+ + + +

The layout algorithm also checks for invalid layouts where the layout would +not visually correspond to how the compiler interprets the tokens. In +particular, it is illegal to indent less than the layout context or to put +comments into the indentation (because of tabs or potential unicode +characters). For example, the program: +

fun equal( x : int, y : int ) : io bool {   
+    print("calculate equality")
+  result = if (x == y) then True   // wrong: too little indentation
+  /* wrong */      else False
+    result
+}  
+fun equal( x : intstd/core/types/int: V, y : intstd/core/types/int: V ) : iostd/core/io: E boolstd/core/types/bool: V {   
+    print("calculate equality")
+  result = if (x == y) then Truestd/core/types/True: bool   // wrong: too little indentation
+  /* wrong */      else Falsestd/core/types/False: bool
+    result
+}  
+
+ + + +

is rejected. In order to facilitate code generation or source code +compression, compilers are also required to support a mode where the layout +rule is not applied and no braces or semicolons are inserted. A recognized command +line flag for that mode should be --nolayout. +

4.3.1. The layout algorithm

+

To define the layout algorithm formally, we first establish some terminology: +

+
    +
  • A new line is started after every linefeed character. +
  • +
  • Any non-white token is called a lexeme, where a line without lexemes +is called blank. +
  • +
  • The indentation of a lexeme is the column number of its first character on +that line (starting at 1), and the indentation of a line is the indentation +of the first lexeme on the line. +
  • +
  • A lexeme is an expression continuation if it is the first lexeme on a line, +and the lexeme is a start continuation token, or the previous lexeme is an +end continuation token (as defined in the previous section). +
+ +

Because braces can be nested, we use a layout stack of strictly +increasing indentations. The top indentation on the layout stack holds the +layout indentation. The initial layout stack contains the single +value 0 (which is never popped). We now proceed through the token stream +where we perform the following operations in order: first brace insertion, +then layout stack operations, and finally semicolon insertion: +

+
    +
  • +

    Brace insertion: For each non-blank line, consider the first lexeme on the line. +If the indentation is larger than the layout indentation, and the lexeme +is not an expression continuation, then insert an open brace { before the lexeme. +If the indention is less than the layout indentation, and the lexeme is not already a +closing brace, insert a closing brace } before the lexeme. +

  • +
  • +

    Layout stack operations: If the previous lexeme was an +open brace { or the start of the lexical token sequence, we push the +indentation of the current lexeme on the layout stack. The pushed indentation +must be larger than the previous layout indentation (unless the current lexeme +is a closing brace). When a closing brace } is encountered the top +indentation is popped from the layout stack. +

  • +
  • +

    Semicolon insertion: For each non-blank line, the +indentation must be equal or larger to the layout indentation. +If the indentation is equal to the layout indentation, and the first +lexeme on the line is not an expression continuation, a semicolon +is inserted before the lexeme. +Also, a semicolon is always inserted before a closing brace } and +before the end of the token sequence. +

+ +

As defined, braces are inserted around any indented blocks, semicolons +are inserted whenever statements or declarations are +aligned (unless the lexeme happens to be a clear expression continuation). To +simplify the grammar specification, a semicolon is also always inserted before +a closing brace and the end of the source. This allows us to specify many +grammar elements as ended by semicolons instead of separated by semicolons +which is more difficult to specify for a LALR(1) grammar. +

+

The layout can be implemented as a separate transformation on the lexical token +stream (see the 50 line Haskell implementation in the Koka compiler), +or directly as part of the lexer (see the Flex implementation) +

4.3.2. Implementation

+

There is a full Flex (Lex) implementation of lexical +analysis and the layout algorithm. +Ultimately, the Flex implementation serves as the +specification, and this document and the Flex implementation should +always be in agreement. +

4.4. Context-free syntax

+

The grammar specification starts with the non terminal module which draws +its lexical tokens from lex where all whitespace tokens are implicitly +ignored. +

4.4.1. Modules

+ + + + + + + + + +
module[ lex ] ::= [ moduledecl ] modulebody
 
moduledecl ::= semis moduleid
moduleid ::= qvarid | varid
 
modulebody ::= { semis declarations } semis
| semis declarations
 
semis ::= { ; }
semi ::= ; semis

4.4.2. Top level declarations

+ + + + + + + + + + + + + + + +
declarations ::= { importdecl } { fixitydecl } topdecls
 
importdecl ::= [ pub ] import [ moduleid = ] moduleid semi
 
fixitydecl ::= [ pub ] fixity integer identifier { , identifier } semi
fixity ::= infixl | infixr | infix
 
topdecls ::= { topdecl semi }
topdecl ::= [ pub ] puredecl
| [ pub ] aliasdecl
| [ pub ] externdecl
| [ pubabstract ] typedecl
| [ pubabstract ] effectdecl
 
pub ::= pub
pubabstract ::= pub | abstract

4.4.3. Type Declarations

+ + + + + + + + + + + + + + + + +
aliasdecl ::= alias typeid [ typeparams ] [ kannot ] = type
 
typedecl ::= typemod type typeid [ typeparams ] [ kannot ] [ typebody ]
| structmod struct typeid [ typeparams ] [ kannot ] [ conparams ]
 
typemod ::= co | rec | open | extendstd/core/sslice/extend: (slice : sslice, count : int) -> sslice | structmod
structmod ::= value | reference
 
typeid ::= varid | [] | ( { , } ) | < > | < | >
 
typeparams ::= < [ tbinders ] >
tbinders ::= tbinder { , tbinder }
tbinder ::= varid [ kannot ]
typebody ::= { semis { constructor semi } }
 
constructor ::= [ pub ] [ con ] conid [ typeparams ] [ conparams ]
conparams ::= { semis { parameter semi } }

4.4.4. Value and Function Declarations

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
puredecl ::= [ inlinemod ] val valdecl
| [ inlinemod ] fun fundecl
inlinemod ::= inline | noinline
 
valdecl ::= binder = blockexpr
binder ::= identifier [ : type ]
 
fundecl ::= funid funbody
funbody ::= funparam blockexpr
funparam ::= [ typeparams ] pparameters [ : tresult ] [ qualifier ]
funid ::= identifier
| [ { , } ] (indexing operator)
 
parameters ::= ( [ parameter { , parameter } ] )
parameter ::= [ borrow ] paramid [ : type ] [ = expr ]
 
pparameters ::= ( [ pparameter { , pparameter } ] ) (pattern matching parameters)
pparameter ::= [ borrow ] pattern [ : type ] [ = expr ]
 
paramid ::= identifier | wildcard
borrow ::= ^ (not allowed from conparams)
 
qidentifier ::= qvarid | qidop | identifier
identifier ::= varid | idop
 
qoperator ::= op
qconstructor ::= conid | qconid

4.4.5. Statements

+ + + + + + + + + + +
block ::= { semis { statement semi } }
 
statement ::= decl
| withstat
| withstat in expr
| returnexpr
| basicexpr
 
decl ::= fun fundecl
| val apattern = blockexpr (local values can use a pattern binding)
| var binder := blockexpr

4.4.6. Expressions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
blockexpr ::= expr (block is interpreted as statements)
 
expr ::= withexpr
block (interpreted as fn(){...})
returnexpr
valexpr
basicexpr
 
basicexpr ::= ifexpr
| fnexpr
| matchexpr
| handlerexpr
| opexpr
 
ifexpr ::= if ntlexpr then blockexpr { elif } [ else blockexpr ]
| if ntlexpr return expr
elif ::= elif ntlexpr then blockexpr
 
matchexpr ::= match ntlexpr { semis { matchrule semi } }
returnexpr ::= return expr
fnexpr ::= fn funbody (anonymous lambda expression)
valexpr ::= val apattern = blockexpr in expr
 
withexpr ::= withstat in expr
withstat ::= with basicexpr
with binder <- basicexpr
with [ override ] heff opclause (with single operation)
with binder <- heff opclause (with named single operation)

4.4.7. Operator expressions

+

For simplicity, we parse all operators as if they are left associative with +the same precedence. We assume that a separate pass in the compiler will use +the fixity declarations that are in scope to properly associate all operators +in an expressions. +

+ + + + + + + + + + + + + + + + +
opexpr ::= prefixexpr { qoperator prefixexpr }
prefixexpr ::= { ! | ~ } appexpr
appexpr ::= appexpr ( [ arguments ] ) (regular application)
| appexpr [ [ arguments ] ] (index operation)
| appexpr (fnexpr | block) (trailing lambda expression)
| appexpr . atom
| atom
 
ntlexpr ::= ntlprefixexpr { qoperator ntlprefixexpr } (non trailing lambda expression)
ntlprefixexpr ::= { ! | ~ } ntlappexpr
ntlappexpr ::= ntlappexpr ( [ arguments ] ) (regular application)
| ntlappexpr [ [ arguments ] ] (index operation)
| ntlappexpr . atom
| atom
 
arguments ::= argument { , argument }
argument ::= [ identifier = ] expr

4.4.8. Atomic expressions

+ + + + + + + + + + + + + +
atom ::= qidentifier
| qconstructor
| literal
| mask
| ( ) (unit)
| ( annexpr ) (parenthesized expression)
| ( annexprs ) (tuple expression)
| [ [ annexpr { , annexprs } [ , ] ] ] (list expression)
 
literal ::= natural | float | charlit | stringlit
mask ::= mask [ behind ] < tbasic >
 
annexprs ::= annexpr { , annexpr }
annexpr ::= expr [ : typescheme ]

4.4.9. Matching

+ + + + + + + + + + + + + + +
matchrule ::= patterns [ | expr ] -> blockexpr
 
apattern ::= pattern [ typescheme ]
pattern ::= identifier
| identifier as apattern (named pattern)
| qconstructor [( [ patargs ] )]
| ( [ apatterns ] ) (unit, parenthesized pattern, tuple pattern)
| [ [ apatterns ] ] (list pattern)
| literal
| wildcard
 
patterns ::= pattern { , pattern }
apatterns ::= apattern { , apattern }
patargs ::= patarg { , patarg }
patarg ::= [ identifier = ] apattern (possibly named parameter)

4.4.10. Effect Declarations

+ + + + + + + + +
effectdecl ::= [ named ] effectmod effect varid [ typeparams ] [ kannot ] [ opdecls ]
| [ named ] effectmod effect [ typeparams ] [ kannot ] opdecl
| named effectmod effect varid [ typeparams ] [ kannot ] in type [ opdecls ]
effectmod ::= [ linear ] [ rec ]
named ::= named
 
opdecls ::= { semis { opdecl semi } }
opdecl ::= [ pub ] val identifier [ typeparams ] : tatom
| [ pub ] (fun | ctl) identifier [ typeparams ] parameters : tatom

4.4.11. Handler Expressions

+ + + + + + + + + + + + + + + + + + + +
handlerexpr ::= [ override ] handler heff opclauses
| [ override ] handle heff ( expr ) opclauses
| named handler heff opclauses
| named handle heff ( expr ) opclauses
heff ::= [ < tbasic > ]
 
opclauses ::= { semis { opclausex semi } }
opclausex | opclause
| finallystd/core/hnd/finally: forall<a,e> (fin : () -> e (), action : () -> e a) -> e a blockexpr
| initiallystd/core/hnd/initially: forall<a,e> (init : (int) -> e (), action : () -> e a) -> e a ( oparg ) blockexpr
 
opclause ::= val qidentifier [ type ] = blockexpr
| fun qidentifier opargs blockexpr
| [ ctlmod ]ctl qidentifier opargs blockexpr
| return ( oparg ) blockexpr
ctlmod ::= final | raw
 
opargs ::= ( [ oparg { , oparg } ] )
oparg ::= paramid [ : type ]

4.4.12. Type schemes

+ + + + + + + + + +
typescheme ::= somes foralls tarrow [ qualifier ]
type ::= foralls tarrow [ qualifier ]
 
foralls ::= [ forall typeparams ]
some ::= [ some typeparams ]
 
qualifier ::= with ( predicates )
 
predicates ::= predicate { , predicate }
predicate ::= typeapp (interface)

4.4.13. Types

+ + + + + + + + + + + + + + + + + + + + + + +
tarrow ::= tatom [ -> tresult ]
tresult ::= tatom [ tbasic ]
 
tatom ::= tbasic
| < anntype { , anntype } [ | tatom ] >
| < >
 
tbasic ::= typeapp
| ( ) (unit type)
| ( tparam ) (parenthesized type or type parameter)
| ( tparam { , tparam } ) (tuple type or parameters)
| [ anntype ] (list type)
 
typeapp ::= typecon [ < anntype { , anntype } > ]
 
typecon ::= varid | qvarid
| wildcard
| ( , { , } ) (tuple constructor)
| [ ] (list constructor)
| ( -> ) (function constructor)
 
tparam ::= [ varid : ] anntype
anntype ::= type [ kannot ]

4.4.14. Kinds

+ + + + + + + + + + + + + +
kannot ::= :: kind
 
kind ::= ( kind { , kind } ) -> kind
| katom -> kind
| katom
 
katom ::= V (value type)
| X (effect type)
| E (effect row)
| H (heap type)
| P (predicate type)
| S (scope type)
| HX (handled effect type)
| HX1 (handled linear effect type)

4.4.15. Implementation

+

As a companion to the Flex lexical implementation, there is a full +Bison(Yacc) LALR(1) implementation +available. Again, the Bison parser functions +as the specification of the grammar and this document should always +be in agreement with that implementation. +

+

References

+
+
[1]Dariusz Biernacki, Maciej Piróg, Piotr Polesiuk, and Filip Sieczkowski. “Handle with Care: Relational Interpretation of Algebraic Effects and Handlers.” Proc. ACM Program. Lang. 2 (POPL’17 issue): 8:1–8:30. Dec. 2017. doi:10.1145/3158096🔎
+
[2]Nicholas Boucher, and Ross Anderson. “Trojan Source: Invisible Vulnerabilities.” Preprint. 2021. arXiv:cs.CR/2111.00169🔎
+
[3]Leo J Guibas, and Robert Sedgewick. “A Dichromatic Framework for Balanced Trees.” In 19th Annual Symposium on Foundations of Computer Science (sfcs 1978), 8–21. IEEE. 1978. 🔎
+
[4]Carl A. Gunter, Didier Rémy, and Jon G. Riecke. “A Generalization of Exceptions and Control in ML-like Languages.” In Proceedings of the Seventh International Conference on Functional Programming Languages and Computer Architecture, 12–23. FPCA ’95. ACM, La Jolla, California, USA. 1995. doi:10.1145/224164.224173🔎
+
[5]Daniel Hillerström, and Sam Lindley. “Liberating Effects with Rows and Handlers.” In Proceedings of the 1st International Workshop on Type-Driven Development, 15–27. TyDe 2016. Nara, Japan. 2016. doi:10.1145/2976022.2976033🔎
+
[6]Gérard P. Huet. “The Zipper.” Journal of Functional Programming 7 (5): 549–554. 1997. 🔎
+
[7]Donald E. Knuth. The Art of Computer Programming, Volume 1 (3rd Ed.): Fundamental Algorithms. Addison Wesley Longman Publishing Co., Inc. 1997. 🔎
+
[8]Daan Leijen. “Extensible Records with Scoped Labels.” In Proceedings of the 2005 Symposium on Trends in Functional Programming, 297–312. 2005. 🔎
+
[9]Daan Leijen. “Structured Asynchrony with Algebraic Effects.” In Proceedings of the 2nd ACM SIGPLAN International Workshop on Type-Driven Development, 16–29. TyDe 2017. Oxford, UK. 2017. doi:10.1145/3122975.3122977🔎
+
[10]Daan Leijen. “Type Directed Compilation of Row-Typed Algebraic Effects.” In Proceedings of the 44th ACM SIGPLAN Symposium on Principles of Programming Languages (POPL’17), 486–499. Paris, France. Jan. 2017. doi:10.1145/3009837.3009872🔎
+
[11]Daan Leijen, and Anton Lorenzen. Tail Recursion Modulo Context – An Equational Approach. MSR-TR-2022-18. Microsoft Research. Jul. 2022. 🔎
+
[12]Daan Leijen, and Anton Lorenzen. “Tail Recursion Modulo Context: An Equational Approach.” Proc. ACM Program. Lang. 7 (POPL). Jan. 2023. doi:10.1145/3571233. See also [11]🔎
+
[13]Anton Lorenzen, and Daan Leijen. Reference Counting with Frame Limited Reuse. MSR-TR-2021-30. Microsoft Research. Nov. 2022. https://​www.​microsoft.​com/​en-​us/​research/​publication/​reference-​counting-​with-​frame-​limited-​reuse-​extended-​version/​🔎
+
[14]Anton Lorenzen, Daan Leijen, and Wouter Swierstra. FP$\mathpre{^2}$: Fully in-Place Functional Programming. MSR-TR-2023-19. Microsoft Research. May 2023. https://​www.​microsoft.​com/​en-​us/​research/​publication/​fp2-​fully-​in-​place-​functional-​programming🔎
+
[15]Anton Lorenzen, Daan Leijen, and Wouter Swierstra. “FP$\mathpre{^2}$: Fully in-Place Functional Programming.” In Proceedings of the 28th ACM SIGPLAN International Conference on Functional Programming (ICFP’2023). ICFP’23. Seattle, WA, USA. Sep. 2023. See also [14]🔎
+
[16]Prabhaker Mateti, and Ravi Manghirmalani. “Morris’ Tree Traversal Algorithm Reconsidered.” Science of Computer Programming 11 (1): 29–43. 1988. doi:10.1016/0167-6423(88)90063-9🔎
+
[17]Conor McBride. “The Derivative of a Regular Type Is Its Type of One-Hole Contexts.” 2001. http://​strictlypositive.​org/​diff.​pdf. (Extended Abstract). 🔎
+
[18]Joseph M. Morris. “Traversing Binary Trees Simply and Cheaply.” Information Processing Letters 9 (5): 197–200. 1979. doi:10.1016/0020-0190(79)90068-1🔎
+
[19]Chris Okasaki. “Red-Black Trees in a Functional Setting.” Journal of Functional Programming 9 (4). Cambridge University Press: 471–477. 1999. doi:10.1017/S0956796899003494🔎
+
[20]Chris Okasaki. Purely Functional Data Structures. Colombia University, New York. Jun. 1999. 🔎
+
[21]Gordon D. Plotkin, and Matija Pretnar. “Handlers of Algebraic Effects.” In 18th European Symposium on Programming Languages and Systems, 80–94. ESOP’09. York, UK. Mar. 2009. doi:10.1007/978-3-642-00590-9_7🔎
+
[22]Alex Reinking, Ningning Xie, Leonardo de Moura, and Daan Leijen. “Perceus: Garbage Free Reference Counting with Reuse.” In Proceedings of the 42nd ACM SIGPLAN International Conference on Programming Language Design and Implementation, 96–111. PLDI 2021. Virtual, Canada. 2021. doi:10.1145/3453483.3454032🔎
+
[23]Ningning Xie, Jonathan Brachthäuser, Phillip Schuster, Daniel Hillerström, and Daan Leijen. “Effect Handlers, Evidently.” In Proceedings of the 25th ACM SIGPLAN International Conference on Functional Programming (ICFP’2020). ICFP ’20. Jersey City, NJ. Aug. 2020. 🔎
+
[24]Ningning Xie, and Daan Leijen. Generized Evidence Passing for Effect Handlers – Efficient Compilation of Effect Handlers to C. MSR-TR-2021-5. Microsoft Research. Mar. 2021. https://​www.​microsoft.​com/​en-​us/​research/​publication/​generalized-​evidence-​passing-​for-​effect-​handlers/​🔎
+
[25]Ningning Xie, and Daan Leijen. “Generized Evidence Passing for Effect Handlers – Efficient Compilation of Effect Handlers to C.” In Proceedings of the 26th ACM SIGPLAN International Conference on Functional Programming (ICFP’2021). ICFP ’21. Virtual. Aug. 2021. 🔎

Appendix

A. Full grammar specification

A.1. Lexical syntax

+

A.2. Context-free syntax

+
+
+
+ +
+

1.This is used for example in the Flex implementation. +In particular, we only need to adapt the char definition: +

+ + + + + + + + + + + + + + + +
char ::= unicode<!control | surrogate | bidi>
unicode ::= x00..x7F (ASCII)
| (xC2..xDF) cont
| xE0 (xA0..xBF) cont (exclude overlong encodings)
| (xE1..xEF) cont cont
| xF0 (x90..xBF) cont cont (exclude overlong encodings)
| (xF1..xF3) cont cont cont
| xF4 (x80..x8F) cont cont (no codepoint larger than x10FFFF)
cont ::= x80..xBF
surrogate ::= xED (xA0..xBF) cont
control ::= x00..x1F
| x7F
| xC2 (x80..x9F)
bidi ::= xE2 0x80 (0x8E..0x8F) (left-to-right mark (u200E) and right-to-left mark (u200F))
| xE2 0x80 (0xAA..0xAE) (left-to-right embedding (u202A) up to right-to-left override (u202E))
| xE2 0x81 (0xA6..0xA9) (left-to-right isolate (u2066) up to pop directional isolate (u2069))
+

+ -

. -

-
- + - \ No newline at end of file + diff --git a/doc/index.html b/doc/index.html index a01c90cf4..e031bb088 100644 --- a/doc/index.html +++ b/doc/index.html @@ -1,50 +1,1446 @@ - - + - - + + + + + The Koka Programming Language + + + + + + + + + + +
+
+
+ +

koka-logo + +

+
+

Koka
+A Functional Language with Effect Types and Handlers

+
// A generator effect with one operation
+effect yield<a>
+  fun yield( x : a ) : ()
+
+// Traverse a list and yield the elements
+fun traverse( xs : list<a> ) : yield<a> () 
+  match xs
+    Cons(x,xx) -> { yield(x); traverse(xx) }
+    Nil        -> ()
+
+fun main() : console () 
+  with fun yield(i : int)
+    println("yielded " ++ i.show)   
+  [1,2,3].traverse
+// A generator effect with one operation
+effectindex/yield: (V, E, V) -> V yieldindex/yield: (V, E, V) -> V<aa: V>
+  fun yield( xx: $229 : aa: V ) : (std/core/types/unit: V)std/core/types/unit: V
 
-
-
+// Traverse a list and yield the elements
+fun traverseindex/traverse: forall<a> (xs : list<a>) -> (yield<a>) ()( xsxs: list<$282> : liststd/core/types/list: V -> V<aa: V> )result: -> (yield<309>) () : yieldindex/yield: (V, E, V) -> V<aa: V> (std/core/types/unit: V)std/core/types/unit: V 
+  match xsxs: list<$282>
+    Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $282,xxxx: list<$282>) -> { yieldindex/yield: (x : $282) -> (yield<$282>) ()(xx: $282); traverseindex/traverse: (xs : list<$282>) -> (yield<$282>) ()(xxxx: list<$282>) }
+    Nilstd/core/types/Nil: forall<a> list<a>        -> (std/core/types/Unit: ())std/core/types/Unit: ()
+
+fun mainindex/main: () -> console ()()result: -> console () : consolestd/core/console/console: X (std/core/types/unit: V)std/core/types/unit: V 
+  withhandler: (() -> <yield<int>,console> ()) -> console () fun yieldyield: (i : int) -> console ()(ii: int : intstd/core/types/int: V)
+    printlnstd/core/console/string/println: (s : string) -> console ()("yielded "literal: string
count= 8
++std/core/types/(++): (x : string, y : string) -> console string ii: int.showstd/core/int/show: (i : int) -> console string) + [std/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
,2literal: int
dec = 2
hex8 = 0x02
bit8 = 0b00000010
,3literal: int
dec = 3
hex8 = 0x03
bit8 = 0b00000011
]std/core/types/Nil: forall<a> list<a>.traverseindex/traverse: (xs : list<int>) -> <yield<int>,console> ()
+
+
+
+ +

Welcome to Koka – a strongly typed functional-style language with effect types and handlers. +

+

Install +Get Started +Documentation +Github

+
+

Note: Koka v3 is a research language that is currently under development +and not ready for production use. +Nevertheless, the language is stable and the compiler +implements the full specification. The main things lacking at the moment are +(async) libraries and package management. +

+
+

News: +

+
    +
  • +

    2024-02-14: Koka v3.1.0 released with a concurrent build system +and improved language service over the stdio protocol. Redesign of named effect +typing to match the formal system more closely. See samples/handlers/named for examples. +

  • +
  • +

    2024-01-25: Koka v3.0.4 released with improved VS Code hover and inlay information. +Splits std/core in multiple modules, fixes bug in infinite expansion for implicits +and various other small improvements. +

  • +
  • +

    2024-01-13: Koka v3.0.1 released with improved VS Code integration and inlay hints. Initial support for +locally qualified names and implicit parameters (see the samples/syntax). Various small bug fixes. +

  • +
  • +

    2023-12-30: Koka v2.6.0 released with VS Code language integration with type information, jump to definition, +run test functions directly from the editor, automatic Koka installation, and many more things. +Special thanks to Tim Whiting and Fredrik Wieczerkowski for all their work on making this possible! +

  • +
  • +

    2023-12-27: Update of the technical report on "The functional essence of binary trees" where we use fully-in-place programming and +the new hole contexts to create fully verified functional implementations of binary search tree +algorithms with performance on par with imperative C implementations. +

  • +
  • +

    2023-07-03: Koka v2.4.2 released: add support for fip and fbip keywords described +in “FP2: Fully in-Place Functional Programming” +(ICFP'23) [pdf]. +Various fixes and performance improvements. +

  • +
  • +

    2021-02-04 (pinned) The Context Free +youtube channel posted a short and fun video +about effects in Koka (and 12 (!) other languages). +

  • +
  • +

    2021-09-01 (pinned) The ICFP'21 tutorial +“Programming with Effect Handlers and FBIP in Koka” is now available on +youtube. +

  • +
  • +

    2022-02-07: Koka v2.4.0 released: improved specialization and int operations, add rbtree-fbip sample, +improve grammar (pub (instead of public, remove private (as everything is private by default now)), +final ctl (instead of brk), underscores in number literals, etc), rename double to float64, various bug fixes. +

  • +
  • +

    2021-12-27: Koka v2.3.8 released: improved int performance, various bug fixes, update wasm backend, +initial conan support, fix js backend. +

  • +
  • +

    2021-11-26: Koka v2.3.6 released: +maybe-like types are already value types, but now also no longer need heap allocation +if not nested (and [Just(1)] uses the same heap space as [1]), +improved atomic refcounting (by Anton Lorenzen), improved specialization (by Steven Fontanella), +various small fixes, add std/os/readline, fix build on freeBSD +

  • +
  • +

    2021-10-15: Koka v2.3.2 released, with initial wasm support +(use --target=wasm, and install emscripten and wasmtime), +improved reuse specialization (by Anton Lorenzen), and various bug fixes. +

  • +
  • +

    2021-09-29: Koka v2.3.1 released, with improved TRMC optimizations, and improved reuse +(the rbtree benchmark is as fast as C++ now), and +faster effect operations. Experimental: allow elision of -> in anonymous +function expressions (e.g. xs.map( fn(x) x + 1 )) and operation clauses. +Command line options changed a bit with .koka as the standard output directory. +

  • +
  • +

    2021-09-20: Koka v2.3.0 released, with new +brace elision and if/match +conditions without parenthesis. Updated the javascript backend +using ES6 modules and BigInt. new module std/num/int64, improved effect operation performance. +

  • +
  • +

    2021-09-05: Koka v2.2.1 released, with initial parallel tasks, the binary-trees benchmark, and +brace elision. +

  • +
  • +

    2021-08-26: Koka v2.2.0 released, improved simplification (by Rashika B), cross-module specialization (Steven Fontanella), +and borrowing annotations with improved reuse analysis (Anton Lorenzen). +

  • +
  • +

    2021-08-26: At 12:30 EST was the live Koka tutorial at +ICFP'21, +see it on youtube. +

  • +
  • +

    2021-08-23: “Generalized Evidence Passing for Effect Handlers”, by Ningning Xie and Daan Leijen presented at ICFP'21. +See it on youtube +or read the paper. +

  • +
  • +

    2021-08-22: “First-class Named Effect Handlers”, by Youyou Cong, Ningning Xie, and Daan Leijen presented at HOPE'21. +See it on youtube +or read the paper. +

  • +
  • +

    2021-06-23: Koka v2.1.9 released, initial cross-module specialization (by Steven Fontanella). +

  • +
  • +

    2021-06-17: Koka v2.1.8 released, initial Apple M1 support. +

  • +
  • +

    The Perceus paper won a distinguished paper award at PLDI'21! +

  • +
  • +

    2021-06-10: Koka v2.1.6 released. +

  • +
  • +

    2021-05-31: Koka v2.1.4 released. +

  • +
  • +

    2021-05-01: Koka v2.1.2 released. +

  • +
  • +

    2021-03-08: Koka v2.1.1 released. +

  • +
  • +

    2021-02-14: Koka v2.0.16 released. +

  • +
  • +

    2020-12-12: Koka v2.0.14 released. +

  • +
  • +

    2020-12-02: Koka v2.0.12 released. +

  • +
  • +

    2020-11-29: Perceus technical report publised (pdf). +

+

Why Koka?

+
- - +
+ + + + + -index documentation - - -

index▲toc

- -
+

Install

+
+ -

A generator effect with one operation + +

Install with the VS Code editor

+

vscode-install

-

Operations: +

The easiest way to start with Koka is to use the excellent VS Code editor +and install the Koka extension. +Go to the extension panel, search for Koka and +install the official extension as shown on the right.

-

fun yield
-fun yieldindex/yield: forall<a> (x : a) -> (yield<a>) ()
-
. -

fun yield( x : a ) : (yieldindex/yield: (V, E, V) -> V<a>) ()
+

Installing the extension also prompts to install +the latest Koka compiler on your platform +(available for Windows x64, MacOS x64 and arm64, and Linux x64). +

-

Call the fun yieldindex/yield: forall<a> (x : a) -> (yield<a>) () operation of the effect yieldindex/yield: (V, E, V) -> V. -

- -
-

Traverse a list and yield the elements. -

- + +

Once installed, the samples directory is opened. You can also open this +manually from the command panel (Ctrl/Cmd+Shift+P), +and running the Koka: Open samples command (when you start typing the command will surface to the top). +Open for example the basic/caesar.kk file: +When you click run debug (or optimized) Koka compiles and runs the function, +showing the output in the VS Code terminal. +

+

vscode-caesar +

+

Press and hold ctrl+alt (or ctrl+option on MacOS) to show inlay hints – showing inferred +types, fully qualified names, and implicit arguments. +

+
+

vscode-inlay-off +

+

 versus  +

+

vscode-inlay-on

Manual Installation

+

On Windows (x64), open a cmd prompt and use: +

+

+
curl -sSL -o %tmp%\install-koka.bat https://github.com/koka-lang/koka/releases/latest/download/install.bat && %tmp%\install-koka.bat
+

On Linux (x64) and macOS (x64, arm64 (M1/M2)), you can install Koka using: +

+

+
curl -sSL https://github.com/koka-lang/koka/releases/latest/download/install.sh | sh
+

(If you previously installed Koka on macOS using brew, do an brew uninstall koka first). +On other platforms it is usually easy to build Koka from source instead. +

+ + + +

After installation, verify if Koka installed correctly: +

+
$ koka
+ _         _
+| |       | |
+| | _ ___ | | _ __ _
+| |/ / _ \| |/ / _' |  welcome to the koka interactive compiler
+|   ( (_) |   ( (_| |  version 2.4.0, Feb  7 2022, libc x64 (gcc)
+|_|\_\___/|_|\_\__,_|  type :? for help, and :q to quit
+
+loading: std/core
+loading: std/core/types
+loading: std/core/hnd
+>
+

Type :q to exit the interactive environment. +

+

For detailed installation instructions and other platforms see the releases page. +It is also straightforward to build the compiler from source. +

+

Get started with the compiler +

+ + - - \ No newline at end of file + diff --git a/doc/std_core-source.html b/doc/std_core-source.html index 4b9698179..39d76951b 100644 --- a/doc/std_core-source.html +++ b/doc/std_core-source.html @@ -10,11 +10,271 @@ - documentation +core.kk documentation -

+
/*---------------------------------------------------------------------------
+  Copyright 2012-2024, Microsoft Research, Daan Leijen.
+
+  This is free software; you can redistribute it and/or modify it under the
+  terms of the Apache License, Version 2.0. A copy of the License can be
+  found in the LICENSE file at the root of this distribution.
+---------------------------------------------------------------------------*/
+
+/* Core functions.
+
+   This module is implicitly imported and all functions and types
+   are always available.
+   Some types and operations are required to be defined for the compiler
+   to work correctly (i.e. types like `:exn` or `:list`)
+*/
+module std/corestd/core
+
+pub import std/core/typesstd/core/types
+import std/core/undivstd/core/undiv
+import std/core/unsafestd/core/unsafe
+pub import std/core/hndstd/core/hnd
+pub import std/core/exnstd/core/exn
+pub import std/core/boolstd/core/bool
+pub import std/core/orderstd/core/order
+pub import std/core/charstd/core/char
+pub import std/core/intstd/core/int
+pub import std/core/vectorstd/core/vector
+pub import std/core/stringstd/core/string
+pub import std/core/sslicestd/core/sslice
+pub import std/core/liststd/core/list
+pub import std/core/maybestd/core/maybe
+pub import std/core/eitherstd/core/either
+pub import std/core/tuplestd/core/tuple
+pub import std/core/showstd/core/show
+pub import std/core/debugstd/core/debug
+pub import std/core/delayedstd/core/delayed
+pub import std/core/consolestd/core/console
+
+extern import
+  c  file "core/inline/core"
+  cs file "core/inline/core.cs"
+
+// ----------------------------------------------------------------------------
+// Builtin effects
+// ----------------------------------------------------------------------------
+
+// An alias for the empty effect.
+// pub alias total = <>
+
+// An alias for pure effects: a pure function always returns the same result
+// when called with the same arguments but may not terminate or raise an exception.
+pub alias purestd/core/pure: E = <std/core/types/total: Eexnstd/core/exn/exn: (E, V) -> V,divstd/core/types/div: X>
+
+// The `:global-scope` is a special type constant to denote the global scope
+pub type global-scopestd/core/global-scope: S :: S
+
+// The `:net` effect signifies a function may access the network
+pub type netstd/core/net: X :: X
+
+// The `:fsys` effect signifies a function may access the file system
+pub type fsysstd/core/fsys: X :: X
+
+// The `:ui` effect signifies a function may access the graphics system
+pub type uistd/core/ui: X :: X
+
+// The `:blocking` effect signifies that a function may block
+pub type blockingstd/core/blocking: X :: X
+
+// The `:io-total` effect is used for functions that perform arbitrary I/O operations, but are terminating without raising exceptions.
+pub alias io-totalstd/core/io-total: E = <std/core/types/total: Endetstd/core/types/ndet: X,consolestd/core/console/console: X,netstd/core/net: X,fsysstd/core/fsys: X,uistd/core/ui: X,ststd/core/types/st: H -> E<globalstd/core/types/global: H>>
+
+// The `:io-noexn` effect is used for functions that perform arbitrary I/O operations, but raise no exceptions
+pub alias io-noexnstd/core/io-noexn: E = <std/core/types/total: Edivstd/core/types/div: X,io-totalstd/core/io-total: E>
+
+// The `:io` effect is used for functions that perform arbitrary I/O operations.
+pub alias iostd/core/io: E = <std/core/types/total: Eexnstd/core/exn/exn: (E, V) -> V,io-noexnstd/core/io-noexn: E>
+
+// The `:named` effect is the default umbrella effect for named effects
+pub type nmdstd/core/nmd: X :: X
+
+// The `:scope` effect is used to ensure named effects cannot escape the scope of their handler
+pub type scopestd/core/scope: S -> X :: S -> X
+
+
+// ----------------------------------------------------------------------------
+// Standard Functions
+// ----------------------------------------------------------------------------
+
+// Apply a function `f` to a specified argument `x`.
+pub fun applystd/core/apply: forall<a,b,e> (f : (a) -> e b, x : a) -> e b(ff: (_438) -> _439 _440,xx: _438)result: -> 1888 1889
+  ff: (_438) -> _439 _440(xx: _438)
+
+// Compose two functions `f` and `g`.
+pub fun ostd/core/o: forall<a,b,c,e> (f : (a) -> e b, g : (c) -> e a) -> ((x : c) -> e b)(ff: (_531) -> _523 _524,gg: (_522) -> _523 _531)result: -> total (x : 2064) -> 2065 2066
+  fnfn: (x : _522) -> _523 _524(xx: _522) ff: (_531) -> _523 _524(gg: (_522) -> _523 _531(xx: _522))
+
+// The `ignore` function ignores its argument.
+pub fun ignorestd/core/ignore: forall<a> (x : a) -> ()( xx: $484 : aa: V )result: -> total () : (std/core/types/unit: V)std/core/types/unit: V
+  (std/core/types/Unit: ())std/core/types/Unit: ()
+
+// Return a 'constant' function that ignores its argument and always returns the same result
+pub fun conststd/core/const: forall<a,b> (default : a) -> ((x : b) -> a)( defaultdefault: $459 : aa: V )result: -> total (x : 470) -> 469 : totalstd/core/types/total: E (( x : bb: V ) -> astd/core/types/total: E)
+  fnfn: ($460) -> $459(_) defaultdefault: $459
+
+// Concise way to ensure two expressions have the same type.
+pub fun same-typestd/core/same-type: forall<a> (x : a, y : a) -> a( xx: $556 : aa: V, yy: $556 : aa: V )result: -> total 562 : astd/core/types/total: E
+  xx: $556
+
+// ----------------------------------------------------------------------------
+// Control statements
+// ----------------------------------------------------------------------------
+
+// The `while` fun executes `action`  as long as `pred`  is `true`.
+pub fun whilestd/core/while: forall<e> (predicate : () -> <div|e> bool, action : () -> <div|e> ()) -> <div|e> ()( predicatepredicate: () -> <div|$1230> bool : () -> <divstd/core/types/div: X|std/core/types/effect-extend: (X, E) -> Eee: E> boolstd/core/types/bool: V, actionaction: () -> <div|$1230> () : () -> <divstd/core/types/div: X|std/core/types/effect-extend: (X, E) -> Eee: E> (std/core/types/unit: V)std/core/types/unit: V )result: -> <div|1246> () : <divstd/core/types/div: X|std/core/types/effect-extend: (X, E) -> Eee: E> (std/core/types/unit: V)std/core/types/unit: V
+  if predicatepredicate: () -> <div|$1230> bool() then
+    actionaction: () -> <div|$1230> ()()
+    whilestd/core/while: (predicate : () -> <div|$1230> bool, action : () -> <div|$1230> ()) -> <div|$1230> ()(predicatepredicate: () -> <div|$1230> bool, actionaction: () -> <div|$1230> ())std/core/types/Unit: ()
+
+// The `repeat` fun executes `action`  `n`  times.
+pub fun repeatstd/core/repeat: forall<e> (n : int, action : () -> e ()) -> e ()( ^nn: int : intstd/core/types/int: V, actionaction: () -> $1162 () : () -> ee: E (std/core/types/unit: V)std/core/types/unit: V )result: -> 1175 () : ee: E (std/core/types/unit: V)std/core/types/unit: V
+  forstd/core/for: (n : int, action : (int) -> $1162 ()) -> $1162 ()(nn: int) fnfn: (i : int) -> $1162 ()(ii: int)
+    actionaction: () -> $1162 ()()
+
+
+// Executes `action`  for each integer from `start` to `end` (including `end` ).
+// If `start > end`  the function returns without any call to `action` .
+pub fun range/forstd/core/range/for: forall<e> (start : int, end : int, action : (int) -> e ()) -> e ()( ^startstart: int: intstd/core/types/int: V, endend: int : intstd/core/types/int: V, actionaction: (int) -> $1000 () : (intstd/core/types/int: V) -> ee: E (std/core/types/unit: V)std/core/types/unit: V )result: -> 1039 () : ee: E (std/core/types/unit: V)std/core/types/unit: V
+  fun reprep: (i : int) -> $1000 ()( ^ii: int : intstd/core/types/int: V )result: -> $1000 ()
+    if ii: int <=std/core/int/(<=): (x : int, y : int) -> $1000 bool endend: int then
+      actionaction: (int) -> $1000 ()(ii: int)
+      reprep: (i : int) -> $1000 ()(pretend-decreasingstd/core/undiv/pretend-decreasing: (x : int) -> $1000 int(ii: int.incstd/core/int/inc: (i : int) -> $1000 int))std/core/types/Unit: ()
+  reprep: (i : int) -> $1000 ()(startstart: int)
+
+// Executes `action` `n` times for each integer from `0` to `n-1`.
+// If `n <= 0`  the function returns without any call to `action` .
+pub fun forstd/core/for: forall<e> (n : int, action : (int) -> e ()) -> e ()( ^nn: int : intstd/core/types/int: V, actionaction: (int) -> $1043 () : (intstd/core/types/int: V) -> ee: E (std/core/types/unit: V)std/core/types/unit: V )result: -> 1058 () : ee: E (std/core/types/unit: V)std/core/types/unit: V
+  range/forstd/core/range/for: (start : int, end : int, action : (int) -> $1043 ()) -> $1043 ()(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
, nn: int -std/core/int/(-): (x : int, y : int) -> $1043 int 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
, actionaction: (int) -> $1043 ()
) + + +// Executes `action` for each integer between `start` to `end` (including `end` ). +// If `start > end` the function returns without any call to `action` . +// If `action` returns `Just`, the iteration is stopped and the result returned +pub fun range/for-whilestd/core/range/for-while: forall<a,e> (start : int, end : int, action : (int) -> e maybe<a>) -> e maybe<a>( startstart: int: intstd/core/types/int: V, endend: int : intstd/core/types/int: V, actionaction: (int) -> $1065 maybe<$1064> : (intstd/core/types/int: V) -> ee: E maybestd/core/types/maybe: V -> V<aa: V> )result: -> 1122 maybe<1121> : ee: E maybestd/core/types/maybe: V -> V<aa: V> + fun reprep: (i : int) -> $1065 maybe<$1064>( ii: int : intstd/core/types/int: V )result: -> $1065 maybe<$1064> + if ii: int <=std/core/int/(<=): (x : int, y : int) -> $1065 bool endend: int then + match actionaction: (int) -> $1065 maybe<$1064>(ii: int) + Nothingstd/core/types/Nothing: forall<a> maybe<a> -> reprep: (i : int) -> $1065 maybe<$1064>(pretend-decreasingstd/core/undiv/pretend-decreasing: (x : int) -> $1065 int(ii: int.incstd/core/int/inc: (i : int) -> $1065 int)) + Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: $1064) -> Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: $1064) + else Nothingstd/core/types/Nothing: forall<a> maybe<a> + reprep: (i : int) -> $1065 maybe<$1064>(startstart: int) + +// Executes `action` for each integer between [0,`n`) (excluding `n` ). +// If `n <= 0` the function returns without any call to `action` . +// If `action` returns `Just`, the iteration is stopped and the result returned +pub fun for-whilestd/core/for-while: forall<a,e> (n : int, action : (int) -> e maybe<a>) -> e maybe<a>( nn: int : intstd/core/types/int: V, actionaction: (int) -> $1130 maybe<$1129> : (intstd/core/types/int: V) -> ee: E maybestd/core/types/maybe: V -> V<aa: V> )result: -> 1151 maybe<1150> : ee: E maybestd/core/types/maybe: V -> V<aa: V> + range/for-whilestd/core/range/for-while: (start : int, end : int, action : (int) -> $1130 maybe<$1129>) -> $1130 maybe<$1129>(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
, nn: int -std/core/int/(-): (x : int, y : int) -> $1130 int 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
, actionaction: (int) -> $1130 maybe<$1129>
) + + +// Fold over the integers between [`start`,`end`] (including `end`). +pub fun range/foldstd/core/range/fold: forall<a,e> (start : int, end : int, init : a, f : (int, a) -> e a) -> e a( startstart: int : intstd/core/types/int: V, endend: int : intstd/core/types/int: V, initinit: $834 : aa: V, ff: (int, $834) -> $835 $834 : (intstd/core/types/int: V,aa: V) -> ee: E aa: V )result: -> 886 885 : ee: E aa: V + if startstart: int >std/core/int/(>): (x : int, y : int) -> $835 bool endend: int then initinit: $834 else + val xx: $834 = ff: (int, $834) -> $835 $834(startstart: int,initinit: $834) + foldstd/core/range/fold: (start : int, end : int, init : $834, f : (int, $834) -> $835 $834) -> $835 $834(pretend-decreasingstd/core/undiv/pretend-decreasing: (x : int) -> $835 int(startstart: int.incstd/core/int/inc: (i : int) -> $835 int), endend: int, xx: $834, ff: (int, $834) -> $835 $834) + +// Fold over the integers between [0,`upto`) (excluding `upto`). +pub fun foldstd/core/fold: forall<a,e> (upto : int, init : a, f : (int, a) -> e a) -> e a( uptoupto: int : intstd/core/types/int: V, initinit: $811 : aa: V, ff: (int, $811) -> $812 $811 : (intstd/core/types/int: V,aa: V) -> ee: E aa: V )result: -> 833 832 : ee: E aa: V + range/foldstd/core/range/fold: (start : int, end : int, init : $811, f : (int, $811) -> $812 $811) -> $812 $811( 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
, uptoupto: int.decstd/core/int/dec: (i : int) -> $812 int, initinit: $811, ff: (int, $811) -> $812 $811
) + + +// Fold over the integers between [`start`,`end`] (including `end`) or until `f` returns `Nothing` +pub fun range/fold-whilestd/core/range/fold-while: forall<a,e> (start : int, end : int, init : a, f : (int, a) -> e maybe<a>) -> e a( startstart: int : intstd/core/types/int: V, endend: int : intstd/core/types/int: V, initinit: $926 : aa: V, ff: (int, $926) -> $927 maybe<$926> : (intstd/core/types/int: V,aa: V) -> ee: E maybestd/core/types/maybe: V -> V<aa: V> )result: -> 983 982 : ee: E aa: V + if startstart: int >std/core/int/(>): (x : int, y : int) -> $927 bool endend: int then initinit: $926 else + match ff: (int, $926) -> $927 maybe<$926>(startstart: int,initinit: $926) + Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: $926) -> range/fold-whilestd/core/range/fold-while: (start : int, end : int, init : $926, f : (int, $926) -> $927 maybe<$926>) -> $927 $926(pretend-decreasingstd/core/undiv/pretend-decreasing: (x : int) -> $927 int(startstart: int.incstd/core/int/inc: (i : int) -> $927 int), endend: int, xx: $926, ff: (int, $926) -> $927 maybe<$926>) + Nothingstd/core/types/Nothing: forall<a> maybe<a> -> initinit: $926 + +// Fold over the integers between [0,`n`) (excluding `n`) or until `f` returns `Nothing` +pub fun fold-whilestd/core/fold-while: forall<a,e> (n : int, init : a, f : (int, a) -> e maybe<a>) -> e a( nn: int : intstd/core/types/int: V, initinit: $903 : aa: V, ff: (int, $903) -> $904 maybe<$903> : (intstd/core/types/int: V,aa: V) -> ee: E maybestd/core/types/maybe: V -> V<aa: V> )result: -> 925 924 : ee: E aa: V + range/fold-whilestd/core/range/fold-while: (start : int, end : int, init : $903, f : (int, $903) -> $904 maybe<$903>) -> $904 $903( 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
, nn: int.decstd/core/int/dec: (i : int) -> $904 int, initinit: $903, ff: (int, $903) -> $904 maybe<$903>
) + + +// ---------------------------------------------------------------------------- +// Generic equality and comparison +// ---------------------------------------------------------------------------- + +// Generic inequality +pub fun (!=)std/core/(!=): forall<a> (x : a, y : a, @implicit/(==) : (a, a) -> bool) -> bool(xx: $587 : aa: V, yy: $587 : aa: V, (@implicit/==)?(==): ($587, $587) -> bool : (aa: V,aa: V) -> boolstd/core/types/bool: V )result: -> total bool : boolstd/core/types/bool: V + notstd/core/types/not: (b : bool) -> bool(xx: $587==?(==): ($587, $587) -> boolyy: $587) + +// Generic equality if `cmp` exists +pub fun cmp/(==)std/core/cmp/(==): forall<a> (x : a, y : a, @implicit/cmp : (a, a) -> order) -> bool(xx: $402 : aa: V, yy: $402 : aa: V, @implicit/cmp?cmp: ($402, $402) -> order : (aa: V,aa: V) -> orderstd/core/types/order: V )result: -> total bool : boolstd/core/types/bool: V + match cmp?cmp: ($402, $402) -> order(xx: $402,yy: $402) + Eqstd/core/types/Eq: order -> Truestd/core/types/True: bool + _ -> Falsestd/core/types/False: bool + +// Generic greater than +pub fun (>)std/core/(>): forall<a> (x : a, y : a, @implicit/cmp : (a, a) -> order) -> bool(xx: $691 : aa: V, yy: $691 : aa: V, @implicit/cmp?cmp: ($691, $691) -> order : (aa: V,aa: V) -> orderstd/core/types/order: V )result: -> total bool : boolstd/core/types/bool: V + cmp?cmp: ($691, $691) -> order(xx: $691,yy: $691) ==std/core/order/(==): (x : order, y : order) -> bool Gtstd/core/types/Gt: order + +// Generic lower than +pub fun (<)std/core/(<): forall<a> (x : a, y : a, @implicit/cmp : (a, a) -> order) -> bool(xx: $631 : aa: V, yy: $631 : aa: V, @implicit/cmp?cmp: ($631, $631) -> order : (aa: V,aa: V) -> orderstd/core/types/order: V )result: -> total bool : boolstd/core/types/bool: V + cmp?cmp: ($631, $631) -> order(xx: $631,yy: $631) ==std/core/order/(==): (x : order, y : order) -> bool Ltstd/core/types/Lt: order + +// Generic greater than or equal +pub fun (>=)std/core/(>=): forall<a> (x : a, y : a, @implicit/cmp : (a, a) -> order) -> bool(xx: $781 : aa: V, yy: $781 : aa: V, @implicit/cmp?cmp: ($781, $781) -> order : (aa: V,aa: V) -> orderstd/core/types/order: V )result: -> total bool : boolstd/core/types/bool: V + yy: $781 <std/core/(<): (x : $781, y : $781, @implicit/cmp : ($781, $781) -> order) -> bool
?cmp=?cmp
xx: $781 + +// Generic lower than or equal +pub fun (<=)std/core/(<=): forall<a> (x : a, y : a, @implicit/cmp : (a, a) -> order) -> bool(xx: $751 : aa: V, yy: $751 : aa: V, @implicit/cmp?cmp: ($751, $751) -> order : (aa: V,aa: V) -> orderstd/core/types/order: V )result: -> total bool : boolstd/core/types/bool: V + yy: $751 >std/core/(>): (x : $751, y : $751, @implicit/cmp : ($751, $751) -> order) -> bool
?cmp=?cmp
xx: $751 + + +// ---------------------------------------------------------------------------- +// Main +// ---------------------------------------------------------------------------- + +// Used by the compiler to wrap main console applications +pub extern main-consolestd/core/main-console: forall<a,e> (main : () -> e a) -> e a : forall<aa: V,ee: E> ( main : () -> ee: E aa: V ) -> ee: E aa: V + c "kk_main_console" + cs inline "Primitive.MainConsole<##1>(#1)" + js inline "(#1)()" + + +// Return the host environment: `dotnet`, `browser`, `webworker`, `node`, or `libc`. +pub extern hoststd/core/host: () -> ndet string() : ndetstd/core/types/ndet: X stringstd/core/types/string: V + c "kk_get_host" + cs inline "\"dotnet\"" + js inline "$std_core_console._host" + + +// The default exception handler +pub fun @default-exn(actionaction: () -> <exn,console|$249> () : () -> <exnstd/core/exn/exn: (E, V) -> V,consolestd/core/console/console: X|std/core/types/effect-extend: (X, E) -> Eee: E> (std/core/types/unit: V)std/core/types/unit: V )result: -> <console|398> () : <consolestd/core/console/console: X|std/core/types/effect-extend: (X, E) -> Eee: E> (std/core/types/unit: V)std/core/types/unit: V + handlehandler: (() -> <exn,console|$249> ()) -> <console|$249> ()( actionaction: () -> <exn,console|$249> () ) + final ctl throw-exnthrow-exn: (exn : exception) -> <console|$249> ()( exnexn: exception : exceptionstd/core/exn/exception: V ) + "uncaught exception: "literal: string
count= 20
.printstd/core/console/string/print: (s : string) -> <console|$249> () + exnexn: exception.printlnstd/core/console/show/println: (x : exception, @implicit/show : (exception) -> string) -> <console|$249> ()
?show=show
+ + +// ---------------------------------------------------------------------------- +// Non determinism +// ---------------------------------------------------------------------------- + +noinline val unique-countstd/core/unique-count: ref<global,int> : refstd/core/types/ref: (H, V) -> V<globalstd/core/types/global: H,intstd/core/types/int: V> = unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <alloc<global>|_584> ref<global,int>) -> ref<global,int>{ refstd/core/types/ref: (value : int) -> <alloc<global>|_584> ref<global,int>(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
)
} + +// Returns a unique integer (modulo 32-bits). +pub fun uniquestd/core/unique: () -> ndet int()result: -> ndet int : ndetstd/core/types/ndet: X intstd/core/types/int: V + unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <read<global>,write<global>|_1224> int) -> ndet int + val uu: int = !std/core/types/ref/(!): (ref : ref<global,int>) -> <read<global>,write<global>|_1224> intunique-countstd/core/unique-count: ref<global,int> + unique-countstd/core/unique-count: ref<global,int> :=std/core/types/set: (ref : ref<global,int>, assigned : int) -> <write<global>,read<global>|_1224> () uu: int+std/core/int/(+): (x : int, y : int) -> <write<global>,read<global>|_1224> int1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
+
uu: int + + +// ---------------------------------------------------------------------------- +// Stream +// ---------------------------------------------------------------------------- + +// A `:stream` is a co-inductive type representing an infinite list of elements. +pub co type streamstd/core/stream: V -> V<aa: V> + con Nextstd/core/Next: forall<a> (head : a, tail : stream<a>) -> stream<a>(headstd/core/stream/head: forall<a> (stream : stream<a>) -> a:aa: V, tailstd/core/stream/tail: forall<a> (stream : stream<a>) -> stream<a>: streamstd/core/stream: V -> V<aa: V> ) + +
diff --git a/doc/std_core.html b/doc/std_core.html index df232c2fd..e2ba816e5 100644 --- a/doc/std_core.html +++ b/doc/std_core.html @@ -15,78 +15,78 @@ -

std/core▲toc

+

std/core▲toc

- - - - - - - - - - - - - - - - - - @@ -112,50 +112,50 @@

Core functions.

This module is implicitly imported and all functions and types are always available. Some types and operations are required to be defined for the compiler - to work correctly (i.e. types like exnstd/core/exn/exn: (E, V) -> V or liststd/core/types/list: V -> V). + to work correctly (i.e. types like exnstd/core/exn/exn: (E, V) -> V or liststd/core/types/list: V -> V).

-
+

The blockingstd/core/blocking: X effect signifies that a function may block.

-
+

The fsysstd/core/fsys: X effect signifies a function may access the file system.

-
+

The global-scopestd/core/global-scope: S is a special type constant to denote the global scope.

-
+

The iostd/core/io: E effect is used for functions that perform arbitrary I/O operations.

-
+

The io-noexnstd/core/io-noexn: E effect is used for functions that perform arbitrary I/O operations, but raise no exceptions.

-
+ -
+

The netstd/core/net: X effect signifies a function may access the network.

-
+

The named effect is the default umbrella effect for named effects.

-
+

An alias for pure effects: a pure function always returns the same result when called with the same arguments but may not terminate or raise an exception.

-
+

The scopestd/core/scope: S -> X effect is used to ensure named effects cannot escape the scope of their handler.

-
+

A streamstd/core/stream: V -> V is a co-inductive type representing an infinite list of elements.

con Next(head : atail : streamstd/core/stream: V -> V<a>)
fun stream/head( ^stream : streamstd/core/stream: V -> V<a> ) : a
@@ -165,50 +165,50 @@

Core functions.

Automatically generated. Retrieves the tail constructor field of the streamstd/core/stream: V -> V type.

-
+

The uistd/core/ui: X effect signifies a function may access the graphics system.

-
fun cmp/(==)( x : a, y : a, ?cmp : (a, a) -> orderstd/core/types/order: V ) : boolstd/core/types/bool: V
+
fun cmp/(==)( x : a, y : a, ?cmp : (a, a) -> orderstd/core/types/order: V ) : boolstd/core/types/bool: V

Generic equality if cmp exists.

-
fun range/fold( start : intstd/core/types/int: V, end : intstd/core/types/int: V, init : a, f : (intstd/core/types/int: V, a) -> e a ) : e a
+
fun range/fold( start : intstd/core/types/int: V, end : intstd/core/types/int: V, init : a, f : (intstd/core/types/int: V, a) -> e a ) : e a

Fold over the integers between [start,end] (including end).

-
+
-

Fold over the integers between [start,end] (including end) or until f returns Nothingstd/core/types/Nothing: forall<a> maybe<a>. +

Fold over the integers between [start,end] (including end) or until f returns Nothingstd/core/types/Nothing: forall<a> maybe<a>.

-
fun range/for( ^start : intstd/core/types/int: V, end : intstd/core/types/int: V, action : (intstd/core/types/int: V) -> e () ) : e ()
+
fun range/for( ^start : intstd/core/types/int: V, end : intstd/core/types/int: V, action : (intstd/core/types/int: V) -> e () ) : e ()

Executes action for each integer from start to end (including end ). If start > end the function returns without any call to action .

-
+

Executes action for each integer between start to end (including end ). If start > end the function returns without any call to action . -If action returns Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>, the iteration is stopped and the result returned. +If action returns Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>, the iteration is stopped and the result returned.

-
fun (!=)( x : a, y : a, ?(==) : (a, a) -> boolstd/core/types/bool: V ) : boolstd/core/types/bool: V
+
fun (!=)( x : a, y : a, ?(==) : (a, a) -> boolstd/core/types/bool: V ) : boolstd/core/types/bool: V

Generic inequality.

-
fun (<)( x : a, y : a, ?cmp : (a, a) -> orderstd/core/types/order: V ) : boolstd/core/types/bool: V
+
fun (<)( x : a, y : a, ?cmp : (a, a) -> orderstd/core/types/order: V ) : boolstd/core/types/bool: V

Generic lower than.

-
fun (<=)( x : a, y : a, ?cmp : (a, a) -> orderstd/core/types/order: V ) : boolstd/core/types/bool: V
+
fun (<=)( x : a, y : a, ?cmp : (a, a) -> orderstd/core/types/order: V ) : boolstd/core/types/bool: V

Generic lower than or equal.

-
fun (>)( x : a, y : a, ?cmp : (a, a) -> orderstd/core/types/order: V ) : boolstd/core/types/bool: V
+
fun (>)( x : a, y : a, ?cmp : (a, a) -> orderstd/core/types/order: V ) : boolstd/core/types/bool: V

Generic greater than.

-
fun (>=)( x : a, y : a, ?cmp : (a, a) -> orderstd/core/types/order: V ) : boolstd/core/types/bool: V
+
fun (>=)( x : a, y : a, ?cmp : (a, a) -> orderstd/core/types/order: V ) : boolstd/core/types/bool: V

Generic greater than or equal.

@@ -220,26 +220,26 @@

Core functions.

Return a ‘constant’ function that ignores its argument and always returns the same result.

-
fun fold( upto : intstd/core/types/int: V, init : a, f : (intstd/core/types/int: V, a) -> e a ) : e a
+
fun fold( upto : intstd/core/types/int: V, init : a, f : (intstd/core/types/int: V, a) -> e a ) : e a

Fold over the integers between [0,upto) (excluding upto).

-
+
-

Fold over the integers between [0,n) (excluding n) or until f returns Nothingstd/core/types/Nothing: forall<a> maybe<a>. +

Fold over the integers between [0,n) (excluding n) or until f returns Nothingstd/core/types/Nothing: forall<a> maybe<a>.

-
fun for( ^n : intstd/core/types/int: V, action : (intstd/core/types/int: V) -> e () ) : e ()
+
fun for( ^n : intstd/core/types/int: V, action : (intstd/core/types/int: V) -> e () ) : e ()

Executes action n times for each integer from 0 to malformed identifier: a dash must be preceded by a letter or digit, and followed by a letter. If n <= 0 the function returns without any call to action .

-
+

Executes action for each integer between [0,n) (excluding n ). If n <= 0 the function returns without any call to action . -If action returns Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>, the iteration is stopped and the result returned. +If action returns Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>, the iteration is stopped and the result returned.

-
+

Return the host environment: dotnet, browser, webworker, node, or libc.

@@ -255,7 +255,7 @@

Core functions.

Compose two functions f and g.

-
fun repeat( ^n : intstd/core/types/int: V, action : () -> e () ) : e ()
+
fun repeat( ^n : intstd/core/types/int: V, action : () -> e () ) : e ()

The repeat fun executes action n times.

@@ -263,15 +263,15 @@

Core functions.

Concise way to ensure two expressions have the same type.

-
+

Returns a unique integer (modulo 32-bits).

-
fun while( predicate : () -> <divstd/core/types/div: X|e> boolstd/core/types/bool: V, action : () -> <divstd/core/types/div: X|e> () ) : <divstd/core/types/div: X|e> ()
+ - + diff --git a/doc/std_core_bool-source.html b/doc/std_core_bool-source.html index 4b9698179..f63d1c63e 100644 --- a/doc/std_core_bool-source.html +++ b/doc/std_core_bool-source.html @@ -10,11 +10,66 @@ - documentation +bool.kk documentation -

+
/*---------------------------------------------------------------------------
+  Copyright 2012-2024, Microsoft Research, Daan Leijen.
+
+  This is free software; you can redistribute it and/or modify it under the
+  terms of the Apache License, Version 2.0. A copy of the License can be
+  found in the LICENSE file at the root of this distribution.
+---------------------------------------------------------------------------*/
+
+// Standard `:bool` functions.
+//
+// Booleans are either `True` or `False`.
+module std/core/boolstd/core/bool
+
+import std/core/typesstd/core/types
+
+// ----------------------------------------------------------------------------
+// Booleans
+// ----------------------------------------------------------------------------
+
+pub fip fun (==)std/core/bool/(==): (x : bool, y : bool) -> bool( xx: bool : boolstd/core/types/bool: V, yy: bool : boolstd/core/types/bool: V)result: -> total bool : boolstd/core/types/bool: V
+  if xx: bool then yy: bool else !std/core/types/bool/(!): (b : bool) -> boolyy: bool
+
+pub fip fun (!=)std/core/bool/(!=): (x : bool, y : bool) -> bool( xx: bool : boolstd/core/types/bool: V, yy: bool : boolstd/core/types/bool: V)result: -> total bool : boolstd/core/types/bool: V
+  if xx: bool then !std/core/types/bool/(!): (b : bool) -> boolyy: bool else yy: bool
+
+pub fip fun (<)std/core/bool/(<): (x : bool, y : bool) -> bool( xx: bool : boolstd/core/types/bool: V, yy: bool : boolstd/core/types/bool: V)result: -> total bool : boolstd/core/types/bool: V
+  (!std/core/types/bool/(!): (b : bool) -> boolxx: bool &&std/core/types/(&&): (x : bool, y : bool) -> bool yy: bool)
+
+pub fip fun (<=)std/core/bool/(<=): (x : bool, y : bool) -> bool( xx: bool : boolstd/core/types/bool: V, yy: bool : boolstd/core/types/bool: V)result: -> total bool : boolstd/core/types/bool: V
+  !std/core/types/bool/(!): (b : bool) -> bool(xx: bool >std/core/bool/(>): (x : bool, y : bool) -> bool yy: bool)
+
+pub fip fun (>)std/core/bool/(>): (x : bool, y : bool) -> bool( xx: bool : boolstd/core/types/bool: V, yy: bool : boolstd/core/types/bool: V)result: -> total bool : boolstd/core/types/bool: V
+  (xx: bool &&std/core/types/(&&): (x : bool, y : bool) -> bool !std/core/types/bool/(!): (b : bool) -> boolyy: bool)
+
+pub fip fun (>=)std/core/bool/(>=): (x : bool, y : bool) -> bool( xx: bool : boolstd/core/types/bool: V, yy: bool : boolstd/core/types/bool: V)result: -> total bool : boolstd/core/types/bool: V
+  !std/core/types/bool/(!): (b : bool) -> bool(xx: bool <std/core/bool/(<): (x : bool, y : bool) -> bool yy: bool)
+
+// Compare two booleans with `False < True`.
+pub fip fun cmpstd/core/bool/cmp: (x : bool, y : bool) -> order( xx: bool : boolstd/core/types/bool: V, yy: bool : boolstd/core/types/bool: V)result: -> total order : orderstd/core/types/order: V
+  if xx: bool <std/core/bool/(<): (x : bool, y : bool) -> bool yy: bool then Ltstd/core/types/Lt: order
+  elif xx: bool >std/core/bool/(>): (x : bool, y : bool) -> bool yy: bool then Gtstd/core/types/Gt: order
+  else Eqstd/core/types/Eq: order
+
+// Order two booleans in ascending order.
+pub fip fun order2std/core/bool/order2: (x : bool, y : bool) -> order2<bool>( xx: bool : boolstd/core/types/bool: V, yy: bool : boolstd/core/types/bool: V )result: -> total order2<bool> : order2std/core/types/order2: V -> V<boolstd/core/types/bool: V>
+  if (xx: bool==std/core/bool/(==): (x : bool, y : bool) -> boolyy: bool) then Eq2std/core/types/Eq2: forall<a> (eq : a) -> order2<a>(xx: bool) elif (xx: bool <std/core/bool/(<): (x : bool, y : bool) -> bool yy: bool) then Lt2std/core/types/Lt2: forall<a> (lt : a, gt : a) -> order2<a>(xx: bool,yy: bool) else Gt2std/core/types/Gt2: forall<a> (lt : a, gt : a) -> order2<a>(yy: bool,xx: bool)
+
+
+// Convert a `:bool` to a string
+pub fun showstd/core/bool/show: (b : bool) -> string( bb: bool : boolstd/core/types/bool: V )result: -> total string : stringstd/core/types/string: V
+  if bb: bool then "True"literal: string
count= 4
else "False"literal: string
count= 5
+ +// Convert a boolean to an `:int` +pub fip fun intstd/core/bool/int: (b : bool) -> int( bb: bool : boolstd/core/types/bool: V )result: -> total int : intstd/core/types/int: V + if bb: bool then 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
else
0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
+
diff --git a/doc/std_core_bool.html b/doc/std_core_bool.html index d25c42fc8..ef3945537 100644 --- a/doc/std_core_bool.html +++ b/doc/std_core_bool.html @@ -15,38 +15,38 @@ -

std/core/bool▲toc

+

std/core/bool▲toc

- - - - - - -
- -

Compare two booleans with Falsestd/core/types/False: bool (<)std/core/bool/(<): (x : bool, y : bool) -> bool Truestd/core/types/True: bool. +

+ + + + + + -
+
-

Convert a boolean to an intstd/core/types/int: V. +

Convert a boolean to an intstd/core/types/int: V.

-
+ -
+ - + diff --git a/doc/std_core_char-source.html b/doc/std_core_char-source.html index 4b9698179..8b5e81691 100644 --- a/doc/std_core_char-source.html +++ b/doc/std_core_char-source.html @@ -10,11 +10,124 @@ - documentation +char.kk documentation -

+
/*---------------------------------------------------------------------------
+  Copyright 2012-2024, Microsoft Research, Daan Leijen.
+
+  This is free software; you can redistribute it and/or modify it under the
+  terms of the Apache License, Version 2.0. A copy of the License can be
+  found in the LICENSE file at the root of this distribution.
+---------------------------------------------------------------------------*/
+
+// Standard `:char` functions.
+//
+// Characters are unicode _codepoint_\/s.
+// This is different from a unicode _grapheme_ which represents a single displayed
+// symbol and can consists of multiple codepoints due to combining characters and marks.
+module std/core/charstd/core/char
+
+import std/core/typesstd/core/types
+import std/core/intstd/core/int
+
+// ----------------------------------------------------------------------------
+// Characters
+// ----------------------------------------------------------------------------
+
+// Are two characters equal?
+pub inline fip extern (==)std/core/char/(==): (char, char) -> bool : (charstd/core/types/char: V,charstd/core/types/char: V) -> boolstd/core/types/bool: V
+  inline "(#1 == #2)"
+  js inline "(#1 === #2)"
+
+// Are two characters not equal?
+pub inline fip extern (!=)std/core/char/(!=): (char, char) -> bool : (charstd/core/types/char: V,charstd/core/types/char: V) -> boolstd/core/types/bool: V
+  inline "(#1 != #2)"
+  js inline "(#1 !== #2)"
+
+// Is a character code point lower or equal to that of another?
+pub inline fip extern (<=)std/core/char/(<=): (char, char) -> bool : (charstd/core/types/char: V,charstd/core/types/char: V) -> boolstd/core/types/bool: V
+  inline "(#1 <= #2)"
+
+// Is a character code point greater or equal to that of another?
+pub inline fip extern (>=)std/core/char/(>=): (char, char) -> bool : (charstd/core/types/char: V,charstd/core/types/char: V) -> boolstd/core/types/bool: V
+  inline "(#1 >= #2)"
+
+// Is a character code point lower to that of another?
+pub inline fip extern (<)std/core/char/(<): (char, char) -> bool  : (charstd/core/types/char: V,charstd/core/types/char: V) -> boolstd/core/types/bool: V
+  inline "(#1 < #2)"
+
+// Is a character code point greater to that of another?
+pub inline fip extern (>)std/core/char/(>): (char, char) -> bool  : (charstd/core/types/char: V,charstd/core/types/char: V) -> boolstd/core/types/bool: V
+  inline "(#1 > #2)"
+
+// Compare character code points.
+pub fip fun cmpstd/core/char/cmp: (x : char, y : char) -> order( xx: char : charstd/core/types/char: V, yy: char : charstd/core/types/char: V )result: -> total order : orderstd/core/types/order: V
+  if xx: char <std/core/char/(<): (char, char) -> bool yy: char then Ltstd/core/types/Lt: order
+  elif xx: char >std/core/char/(>): (char, char) -> bool yy: char then Gtstd/core/types/Gt: order
+  else Eqstd/core/types/Eq: order
+
+// Order two characters in ascending order.
+pub fip fun order2std/core/char/order2: (x : char, y : char) -> order2<char>( xx: char : charstd/core/types/char: V, yy: char : charstd/core/types/char: V )result: -> total order2<char> : order2std/core/types/order2: V -> V<charstd/core/types/char: V>
+  if (xx: char==std/core/char/(==): (char, char) -> boolyy: char) then Eq2std/core/types/Eq2: forall<a> (eq : a) -> order2<a>(xx: char) elif (xx: char <std/core/char/(<): (char, char) -> bool yy: char) then Lt2std/core/types/Lt2: forall<a> (lt : a, gt : a) -> order2<a>(xx: char,yy: char) else Gt2std/core/types/Gt2: forall<a> (lt : a, gt : a) -> order2<a>(yy: char,xx: char)
+
+// Convert a character to its unicode code point
+pub inline fip extern intstd/core/char/int: (char) -> int : (charstd/core/types/char: V) -> intstd/core/types/int: V
+  inline "#1"
+  c "kk_integer_from_int"
+  cs inline "new BigInteger(#1)"
+
+// Convert a unicode code point to a character
+pub inline fip extern int/charstd/core/char/int/char: (i : int) -> char( i : intstd/core/types/int: V) : charstd/core/types/char: V
+  inline "(#1)"
+  c "kk_integer_clamp32"
+  cs inline "Primitive.IntToInt32(#1)"
+
+// Add two character code points
+pub fip fun (+)std/core/char/(+): (c : char, d : char) -> char(cc: char : charstd/core/types/char: V, dd: char : charstd/core/types/char: V)result: -> total char : totalstd/core/types/total: E charstd/core/types/char: V
+  (cc: char.intstd/core/char/int: (char) -> int +std/core/int/(+): (x : int, y : int) -> int dd: char.intstd/core/char/int: (char) -> int).charstd/core/char/int/char: (i : int) -> char
+
+// Subtract two character code points
+pub fip fun (-)std/core/char/(-): (c : char, d : char) -> char(cc: char : charstd/core/types/char: V, dd: char : charstd/core/types/char: V)result: -> total char : totalstd/core/types/total: E charstd/core/types/char: V
+  (cc: char.intstd/core/char/int: (char) -> int -std/core/int/(-): (x : int, y : int) -> int dd: char.intstd/core/char/int: (char) -> int).charstd/core/char/int/char: (i : int) -> char
+
+// Is the character a lower-case ASCII character?
+pub fip fun is-lowerstd/core/char/is-lower: (c : char) -> bool( cc: char : charstd/core/types/char: V )result: -> total bool : boolstd/core/types/bool: V
+  cc: char >=std/core/char/(>=): (char, char) -> bool 'a'literal: char
unicode= u0061
&&std/core/types/(&&): (x : bool, y : bool) -> bool cc: char <=std/core/char/(<=): (char, char) -> bool 'z'literal: char
unicode= u007A
+ +// Is the character an upper-case ASCII character? +pub fip fun is-upperstd/core/char/is-upper: (c : char) -> bool( cc: char : charstd/core/types/char: V )result: -> total bool : boolstd/core/types/bool: V + cc: char >=std/core/char/(>=): (char, char) -> bool 'A'literal: char
unicode= u0041
&&std/core/types/(&&): (x : bool, y : bool) -> bool cc: char <=std/core/char/(<=): (char, char) -> bool 'Z'literal: char
unicode= u005A
+ +// Is the character an ASCII digit ? +pub fip fun is-digitstd/core/char/is-digit: (c : char) -> bool( cc: char : charstd/core/types/char: V )result: -> total bool : boolstd/core/types/bool: V + cc: char >=std/core/char/(>=): (char, char) -> bool '0'literal: char
unicode= u0030
&&std/core/types/(&&): (x : bool, y : bool) -> bool cc: char <=std/core/char/(<=): (char, char) -> bool '9'literal: char
unicode= u0039
+ +// Is the character an ASCII hexa-decimal digit? +pub fip fun is-hex-digitstd/core/char/is-hex-digit: (c : char) -> bool( cc: char : charstd/core/types/char: V )result: -> total bool : boolstd/core/types/bool: V + cc: char.is-digitstd/core/char/is-digit: (c : char) -> bool ||std/core/types/(||): (x : bool, y : bool) -> bool (cc: char >=std/core/char/(>=): (char, char) -> bool 'a'literal: char
unicode= u0061
&&std/core/types/(&&): (x : bool, y : bool) -> bool cc: char <=std/core/char/(<=): (char, char) -> bool 'f'literal: char
unicode= u0066
) ||std/core/types/(||): (x : bool, y : bool) -> bool (cc: char >=std/core/char/(>=): (char, char) -> bool 'A'literal: char
unicode= u0041
&&std/core/types/(&&): (x : bool, y : bool) -> bool cc: char <=std/core/char/(<=): (char, char) -> bool 'F'literal: char
unicode= u0046
) + +// Is the character an ASCII letter? +pub fip fun is-alphastd/core/char/is-alpha: (c : char) -> bool( cc: char : charstd/core/types/char: V )result: -> total bool : boolstd/core/types/bool: V + cc: char.is-lowerstd/core/char/is-lower: (c : char) -> bool ||std/core/types/(||): (x : bool, y : bool) -> bool cc: char.is-upperstd/core/char/is-upper: (c : char) -> bool + +// Is the character ASCII letter or digit? +pub fip fun is-alpha-numstd/core/char/is-alpha-num: (c : char) -> bool( cc: char : charstd/core/types/char: V )result: -> total bool : boolstd/core/types/bool: V + cc: char.is-alphastd/core/char/is-alpha: (c : char) -> bool ||std/core/types/(||): (x : bool, y : bool) -> bool cc: char.is-digitstd/core/char/is-digit: (c : char) -> bool + +// Is the character an ASCII character, e.g. `c <= '\x7F'`? +pub fip fun is-asciistd/core/char/is-ascii: (c : char) -> bool( cc: char : charstd/core/types/char: V )result: -> total bool : boolstd/core/types/bool: V + cc: char <=std/core/char/(<=): (char, char) -> bool '\DEL'literal: char
unicode= u007F
+ +// Is the character an ASCII control character, e.g. `c < ' '`? +pub fip fun is-controlstd/core/char/is-control: (c : char) -> bool( cc: char : charstd/core/types/char: V )result: -> total bool : boolstd/core/types/bool: V + cc: char <std/core/char/(<): (char, char) -> bool ' 'literal: char
unicode= u0020
+ +// Tests if a character is an element of `" \t\n\r"` +pub fip fun is-whitestd/core/char/is-white: (c : char) -> bool( cc: char : charstd/core/types/char: V )result: -> total bool : boolstd/core/types/bool: V + cc: char ==std/core/char/(==): (char, char) -> bool ' 'literal: char
unicode= u0020
||std/core/types/(||): (x : bool, y : bool) -> bool cc: char ==std/core/char/(==): (char, char) -> bool '\t'literal: char
unicode= u0009
||std/core/types/(||): (x : bool, y : bool) -> bool cc: char ==std/core/char/(==): (char, char) -> bool '\n'literal: char
unicode= u000A
||std/core/types/(||): (x : bool, y : bool) -> bool cc: char ==std/core/char/(==): (char, char) -> bool '\r'literal: char
unicode= u000D
+
diff --git a/doc/std_core_char.html b/doc/std_core_char.html index a8fdfce11..10c020bca 100644 --- a/doc/std_core_char.html +++ b/doc/std_core_char.html @@ -15,10 +15,10 @@ -

std/core/char▲toc

+

std/core/char▲toc

-
+

Convert a unicode code point to a character.

-
+ -
+

Add two character code points.

-
+

Subtract two character code points.

-
+

Is a character code point lower to that of another?

-
+

Is a character code point lower or equal to that of another?

-
+ -
+

Is a character code point greater to that of another?

-
+

Is a character code point greater or equal to that of another?

-
+

Compare character code points.

-
+

Convert a character to its unicode code point.

-
+

Is the character an ASCII letter?

-
+

Is the character ASCII letter or digit?

-
+

Is the character an ASCII character, e.g. c <= '\DEL'?

-
+

Is the character an ASCII control character, e.g. c < ' '?

-
+

Is the character an ASCII digit ?

-
+

Is the character an ASCII hexa-decimal digit?

-
+

Is the character a lower-case ASCII character?

-
+

Is the character an upper-case ASCII character?

-
+

Tests if a character is an element of " \t\n\r".

-
+ - + diff --git a/doc/std_core_console-source.html b/doc/std_core_console-source.html index 4b9698179..e06322127 100644 --- a/doc/std_core_console-source.html +++ b/doc/std_core_console-source.html @@ -10,11 +10,94 @@ - documentation +console.kk documentation -

+
/*---------------------------------------------------------------------------
+  Copyright 2012-2024, Microsoft Research, Daan Leijen.
+
+  This is free software; you can redistribute it and/or modify it under the
+  terms of the Apache License, Version 2.0. A copy of the License can be
+  found in the LICENSE file at the root of this distribution.
+---------------------------------------------------------------------------*/
+
+// Standard output to the console.
+module std/core/consolestd/core/console
+
+import std/core/typesstd/core/types
+import std/core/unsafestd/core/unsafe
+import std/core/hndstd/core/hnd
+import std/core/stringstd/core/string
+import std/core/showstd/core/show
+
+extern import
+  js file "inline/console.js"
+
+
+// The console effect signifies that a function may write to the console.
+pub type consolestd/core/console/console: X :: X
+
+
+// ----------------------------------------------------------------------------
+// Print to the console
+// ----------------------------------------------------------------------------
+
+noinline val redirectstd/core/console/redirect: ref<global,maybe<(string) -> console ()>> : refstd/core/types/ref: (H, V) -> V<globalstd/core/types/global: H,maybestd/core/types/maybe: V -> V<(stringstd/core/types/string: V) -> consolestd/core/console/console: X (std/core/types/unit: V)std/core/types/unit: V>> =
+  unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <alloc<global>|_68> ref<global,maybe<(string) -> console ()>>) -> ref<global,maybe<(string) -> console ()>> { refstd/core/types/ref: (value : maybe<(string) -> console ()>) -> <alloc<global>|_68> ref<global,maybe<(string) -> console ()>>(Nothingstd/core/types/Nothing: forall<a> maybe<a>) }
+
+// Redirect `print` and `println` calls to a specified function.
+noinline fun print-redirectstd/core/console/print-redirect: (print : (msg : string) -> console ()) -> <st<global>,console,ndet> ()( printprint: (msg : string) -> console () : (msg : stringstd/core/types/string: V) -> consolestd/core/console/console: X (std/core/types/unit: V)std/core/types/unit: V )result: -> <st<global>,console,ndet> () : <std/core/types/total: Endetstd/core/types/ndet: X,consolestd/core/console/console: X,ststd/core/types/st: H -> E<globalstd/core/types/global: H>> (std/core/types/unit: V)std/core/types/unit: V
+  redirectstd/core/console/redirect: ref<global,maybe<(string) -> console ()>> :=std/core/types/set: (ref : ref<global,maybe<(string) -> console ()>>, assigned : maybe<(string) -> console ()>) -> <write<global>,alloc<global>,console,ndet,read<global>> () Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(printprint: (msg : string) -> console ())
+
+// Print a string to the console, including a final newline character.
+extern xprintslnstd/core/console/xprintsln: (s : string) -> console ()(ss: string : stringstd/core/types/string: V) : consolestd/core/console/console: X (std/core/types/unit: V)std/core/types/unit: V
+  c  "kk_println"
+  cs "Console.WriteLine"
+  js "_println"
+
+// Print a string to the console
+extern xprintsstd/core/console/xprints: (s : string) -> console ()( ss: string : stringstd/core/types/string: V) : consolestd/core/console/console: X (std/core/types/unit: V)std/core/types/unit: V
+  c  "kk_print"
+  cs "Console.Write"
+  js "_print"
+
+// _Unsafe_. This function removes the state effect from the effect of an action
+inline extern unsafe-nostatestd/core/console/unsafe-nostate: forall<a,h> (action : () -> <st<h>,console> a) -> (() -> console a)( action : () -> <std/core/types/total: Eststd/core/types/st: H -> E<hh: H>,consolestd/core/console/console: X> aa: V ) : ((std/core/types/total: E) -> consolestd/core/console/console: X aa: V)
+  inline "#1"
+
+noinline fun printsstd/core/console/prints: (s : string) -> console ()( ss: string : stringstd/core/types/string: V )result: -> console () : consolestd/core/console/console: X (std/core/types/unit: V)std/core/types/unit: V
+  (unsafe-nostatestd/core/console/unsafe-nostate: (action : () -> <st<global>,console> ()) -> console (() -> console ())
+    match !std/core/types/ref/(!): (ref : ref<global,maybe<(string) -> console ()>>) -> <read<global>,console,alloc<_94>,write<global>> maybe<(string) -> console ()>redirectstd/core/console/redirect: ref<global,maybe<(string) -> console ()>>
+      Nothingstd/core/types/Nothing: forall<a> maybe<a> -> xprintsstd/core/console/xprints: (s : string) -> <console,read<global>,alloc<_94>,write<global>> ()(ss: string)
+      Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(ff: (string) -> console ()) -> ff: (string) -> <console,read<global>,alloc<_94>,write<global>> ()(ss: string)
+  )()
+
+noinline fun printslnstd/core/console/printsln: (s : string) -> console ()( ss: string : stringstd/core/types/string: V )result: -> console () : consolestd/core/console/console: X (std/core/types/unit: V)std/core/types/unit: V
+  (unsafe-nostatestd/core/console/unsafe-nostate: (action : () -> <st<global>,console> ()) -> console (() -> console ())
+    match !std/core/types/ref/(!): (ref : ref<global,maybe<(string) -> console ()>>) -> <read<global>,console,alloc<_195>,write<global>> maybe<(string) -> console ()>redirectstd/core/console/redirect: ref<global,maybe<(string) -> console ()>>
+      Nothingstd/core/types/Nothing: forall<a> maybe<a> -> xprintslnstd/core/console/xprintsln: (s : string) -> <console,read<global>,alloc<_195>,write<global>> ()(ss: string)
+      Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(ff: (string) -> console ()) -> { ff: (string) -> <console,read<global>,alloc<_195>,write<global>> ()(ss: string ++std/core/types/(++): (x : string, y : string) -> <console,read<global>,alloc<_195>,write<global>> string "\n"literal: string
count= 1
) } + )(
) + + + +// Print a string to the console. +pub fun string/printstd/core/console/string/print: (s : string) -> console ()(ss: string : stringstd/core/types/string: V)result: -> console () + printsstd/core/console/prints: (s : string) -> console ()(ss: string) + +// Print a value that has a `show` function +pub fun show/printstd/core/console/show/print: forall<a> (x : a, @implicit/show : (a) -> string) -> console ()( xx: $138 : aa: V, @implicit/show?show: ($138) -> string : aa: V -> stringstd/core/types/string: V )result: -> console () : consolestd/core/console/console: X (std/core/types/unit: V)std/core/types/unit: V + printsstd/core/console/prints: (s : string) -> console ()(xx: $138.show?show: ($138) -> console string) + +// Print a string to the console, including a final newline character. +pub fun string/printlnstd/core/console/string/println: (s : string) -> console ()(ss: string : stringstd/core/types/string: V)result: -> console () : consolestd/core/console/console: X (std/core/types/unit: V)std/core/types/unit: V + printslnstd/core/console/printsln: (s : string) -> console ()(ss: string) + +// Print a value that has a `show` function, including a final newline character. +pub fun show/printlnstd/core/console/show/println: forall<a> (x : a, @implicit/show : (a) -> string) -> console ()( xx: $250 : aa: V, @implicit/show?show: ($250) -> string : aa: V -> stringstd/core/types/string: V )result: -> console () : consolestd/core/console/console: X (std/core/types/unit: V)std/core/types/unit: V + printslnstd/core/console/printsln: (s : string) -> console ()(xx: $250.show?show: ($250) -> console string) +
diff --git a/doc/std_core_console.html b/doc/std_core_console.html index 9af951f84..29fc5664e 100644 --- a/doc/std_core_console.html +++ b/doc/std_core_console.html @@ -15,7 +15,7 @@ -

std/core/console▲toc

+

std/core/console▲toc

@@ -26,27 +26,27 @@

Standard output to the console.

.

-
+

The console effect signifies that a function may write to the console.

-
+

Print a value that has a show function.

-
+

Print a value that has a show function, including a final newline character.

-
+

Print a string to the console.

-
+

Print a string to the console, including a final newline character.

- + diff --git a/doc/std_core_debug-source.html b/doc/std_core_debug-source.html index 4b9698179..a5347d1eb 100644 --- a/doc/std_core_debug-source.html +++ b/doc/std_core_debug-source.html @@ -10,11 +10,97 @@ - documentation +debug.kk documentation -

+
/*---------------------------------------------------------------------------
+  Copyright 2023-2024, Microsoft Research, Daan Leijen.
+
+  This is free software; you can redistribute it and/or modify it under the
+  terms of the Apache License, Version 2.0. A copy of the License can be
+  found in the LICENSE file at the root of this distribution.
+---------------------------------------------------------------------------*/
+
+// Core debugging functions.
+module std/core/debugstd/core/debug
+
+import std/core/typesstd/core/types
+import std/core/unsafestd/core/unsafe
+import std/core/hndstd/core/hnd
+import std/core/stringstd/core/string
+import std/core/consolestd/core/console
+
+extern import
+  c file "inline/debug.c"
+
+// ------------------------------------------------------------------------------
+// File locations
+// ------------------------------------------------------------------------------
+
+// Compilation constant that is replaced with the current file's module name
+pub val file/kk-modulestd/core/debug/file/kk-module: string : stringstd/core/types/string: V = ""literal: string
count= 0
+ +// Compilation constant that is replaced with the current line number +pub val file/kk-linestd/core/debug/file/kk-line: string : stringstd/core/types/string: V = ""literal: string
count= 0
+ +// Compilation constant that is replaced with the current file name +pub val file/kk-filestd/core/debug/file/kk-file: string : stringstd/core/types/string: V = ""literal: string
count= 0
+ +pub fun file/kk-file-linestd/core/debug/file/kk-file-line: (@implicit/kk-file : string, @implicit/kk-line : string) -> string( @implicit/kk-file?kk-file: string, @implicit/kk-line?kk-line: string )result: -> total string + @implicit/kk-file?kk-file: string ++std/core/types/(++): (x : string, y : string) -> string "("literal: string
count= 1
++std/core/types/(++): (x : string, y : string) -> string @implicit/kk-line?kk-line: string ++std/core/types/(++): (x : string, y : string) -> string ")"literal: string
count= 1
+ +// ---------------------------------------------------------------------------- +// Trace, assert, todo +// ---------------------------------------------------------------------------- + +extern xtracestd/core/debug/xtrace: (message : string) -> () : ( message : stringstd/core/types/string: V ) -> (std/core/types/unit: V)std/core/types/unit: V + c "kk_trace" + cs "Primitive.Trace" + js "$std_core_console._trace" + +extern xtrace-anystd/core/debug/xtrace-any: forall<a> (message : string, x : a) -> () : forall<aa: V> ( message: stringstd/core/types/string: V, x : aa: V ) -> (std/core/types/unit: V)std/core/types/unit: V + c "kk_trace_any" + cs "Primitive.TraceAny" + js "$std_core_console._trace_any" + +val trace-enabledstd/core/debug/trace-enabled: ref<global,bool> : refstd/core/types/ref: (H, V) -> V<globalstd/core/types/global: H,boolstd/core/types/bool: V> = unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <alloc<global>|_68> ref<global,bool>) -> ref<global,bool>{ refstd/core/types/ref: (value : bool) -> <alloc<global>|_68> ref<global,bool>(Truestd/core/types/True: bool) } + +// Trace a message used for debug purposes. +// The behaviour is system dependent. On a browser and node it uses +// `console.log` by default. +// Disabled if `notrace` is called. +pub fun tracestd/core/debug/trace: (message : string) -> ()( messagemessage: string : stringstd/core/types/string: V )result: -> total () : (std/core/types/unit: V)std/core/types/unit: V + unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <read<global>|_236> ()) -> () + if !std/core/types/ref/(!): (ref : ref<global,bool>) -> <read<global>|_236> booltrace-enabledstd/core/debug/trace-enabled: ref<global,bool> then xtracestd/core/debug/xtrace: (message : string) -> <read<global>|_236> ()(messagemessage: string)std/core/types/Unit: () + +pub fun trace-infostd/core/debug/trace-info: (message : string, @implicit/kk-file-line : string) -> ()( messagemessage: string : stringstd/core/types/string: V, @implicit/kk-file-line?kk-file-line: string : stringstd/core/types/string: V )result: -> total () : (std/core/types/unit: V)std/core/types/unit: V + tracestd/core/debug/trace: (message : string) -> ()(@implicit/kk-file-line?kk-file-line: string ++std/core/types/(++): (x : string, y : string) -> string ": "literal: string
count= 2
++std/core/types/(++): (x : string, y : string) -> string messagemessage: string
) + +pub fun trace-showstd/core/debug/trace-show: forall<a> (x : a, @implicit/show : (a) -> string, @implicit/kk-file-line : string) -> ()( xx: $329 : aa: V, @implicit/show?show: ($329) -> string : aa: V -> stringstd/core/types/string: V, @implicit/kk-file-line?kk-file-line: string : stringstd/core/types/string: V )result: -> total () : (std/core/types/unit: V)std/core/types/unit: V + trace-infostd/core/debug/trace-info: (message : string, @implicit/kk-file-line : string) -> ()
?kk-file-line=?kk-file-line
(xx: $329.show?show: ($329) -> string
) + +pub fun trace-anystd/core/debug/trace-any: forall<a> (message : string, x : a) -> ()( messagemessage: string : stringstd/core/types/string: V, xx: $250 : aa: V )result: -> total () : (std/core/types/unit: V)std/core/types/unit: V + unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <read<global>|_276> ()) -> () + if !std/core/types/ref/(!): (ref : ref<global,bool>) -> <read<global>|_276> booltrace-enabledstd/core/debug/trace-enabled: ref<global,bool> then xtrace-anystd/core/debug/xtrace-any: (message : string, x : $250) -> <read<global>|_276> ()(messagemessage: string,xx: $250)std/core/types/Unit: () + +// Disable tracing completely. +pub noinline fun notracestd/core/debug/notrace: () -> (st<global>) ()()result: -> (st<global>) () : ststd/core/types/st: H -> E<globalstd/core/types/global: H> (std/core/types/unit: V)std/core/types/unit: V + trace-enabledstd/core/debug/trace-enabled: ref<global,bool> :=std/core/types/set: (ref : ref<global,bool>, assigned : bool) -> <write<global>,alloc<global>,read<global>> () Falsestd/core/types/False: bool + +noinline extern unsafe-assert-failstd/core/debug/unsafe-assert-fail: (msg : string) -> ()( msgmsg: string : stringstd/core/types/string: V ) : (std/core/types/unit: V)std/core/types/unit: V + c "kk_assert_fail" + js inline "function() { throw new Error(\"assertion failed: \" + #1) }()" + +pub fun assertstd/core/debug/assert: (message : string, condition : bool, @implicit/kk-file-line : string) -> ()( messagemessage: string : stringstd/core/types/string: V, conditioncondition: bool : boolstd/core/types/bool: V, @implicit/kk-file-line?kk-file-line: string : stringstd/core/types/string: V )result: -> total () : (std/core/types/unit: V)std/core/types/unit: V // Compiler removes assert calls in optimized builds + if !std/core/types/bool/(!): (b : bool) -> boolconditioncondition: bool then unsafe-assert-failstd/core/debug/unsafe-assert-fail: (msg : string) -> ()(kk-file-line?kk-file-line: string ++std/core/types/(++): (x : string, y : string) -> string ": "literal: string
count= 2
++std/core/types/(++): (x : string, y : string) -> string messagemessage: string
)std/core/types/Unit: () + +// Explicitly trigger a breakpoint +pub extern breakpointstd/core/debug/breakpoint: () -> ndet ()() : ndetstd/core/types/ndet: X (std/core/types/unit: V)std/core/types/unit: V { + c "kk_debugger_break" + cs "System.Diagnostics.Debugger.Break" + js inline "(function(){ debugger; })()" +}result: -> ndet ()
diff --git a/doc/std_core_debug.html b/doc/std_core_debug.html index 1ea20c9f9..5ec2823fd 100644 --- a/doc/std_core_debug.html +++ b/doc/std_core_debug.html @@ -15,7 +15,7 @@ -

std/core/debug▲toc

+

std/core/debug▲toc

Core debugging functions. @@ -25,39 +25,39 @@

Core debugging functions.

.

-
+

Compilation constant that is replaced with the current file name.

- -
+ +

Compilation constant that is replaced with the current line number.

-
+

Compilation constant that is replaced with the current file's module name.

- -
+ +

Explicitly trigger a breakpoint.

-
+

Disable tracing completely.

-
fun trace( message : stringstd/core/types/string: V ) : ()
+
fun trace( message : stringstd/core/types/string: V ) : ()

Trace a message used for debug purposes. The behaviour is system dependent. On a browser and node it uses console.log by default. Disabled if notracestd/core/debug/notrace: () -> (st<global>) () is called.

-
fun trace-any( message : stringstd/core/types/string: V, x : a ) : ()
- -
fun trace-show( x : a, ?show : (a) -> stringstd/core/types/string: V, ?kk-file-line : stringstd/core/types/string: V ) : ()
- +
fun trace-any( message : stringstd/core/types/string: V, x : a ) : ()
+ +
fun trace-show( x : a, ?show : (a) -> stringstd/core/types/string: V, ?kk-file-line : stringstd/core/types/string: V ) : ()
+ diff --git a/doc/std_core_delayed-source.html b/doc/std_core_delayed-source.html index 4b9698179..759195f46 100644 --- a/doc/std_core_delayed-source.html +++ b/doc/std_core_delayed-source.html @@ -10,11 +10,67 @@ - documentation +delayed.kk documentation -

+
/*---------------------------------------------------------------------------
+  Copyright 2023-2024, Microsoft Research, Daan Leijen.
+
+  This is free software; you can redistribute it and/or modify it under the
+  terms of the Apache License, Version 2.0. A copy of the License can be
+  found in the LICENSE file at the root of this distribution.
+---------------------------------------------------------------------------*/
+
+// Delayed computations.
+module std/core/delayedstd/core/delayed
+
+import std/core/typesstd/core/types
+import std/core/hndstd/core/hnd
+import std/core/unsafestd/core/unsafe
+
+// ----------------------------------------------------------------------------
+// Delayed values
+// ----------------------------------------------------------------------------
+
+// Delayed (or _lazy_) values are computed (with effect `:e`) only the first time
+// `force` is called and cached afterwards.
+abstract value type delayedstd/core/delayed/delayed: (E, V) -> V<ee: E,aa: V>
+  con XDelaystd/core/delayed/XDelay: forall<e,a> (dref : ref<global,either<() -> e a,a>>) -> delayed<e,a>( drefstd/core/delayed/delayed/dref: forall<e,a> (delayed : delayed<e,a>) -> ref<global,either<() -> e a,a>> : refstd/core/types/ref: (H, V) -> V<globalstd/core/types/global: H,eitherstd/core/types/either: (V, V) -> V<() -> ee: E aa: V,aa: V>> )
+
+// Create a new `:delayed` value.
+pub fun delaystd/core/delayed/delay: forall<a,e> (action : () -> e a) -> delayed<e,a>( actionaction: () -> $115 $114 : () -> ee: E aa: V )result: -> total delayed<162,161> : delayedstd/core/delayed/delayed: (E, V) -> V<ee: E,aa: V>
+  unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <alloc<global>|_133> delayed<$115,$114>) -> delayed<$115,$114>
+    val rr: ref<global,either<() -> $115 $114,$114>> : refstd/core/types/ref: (H, V) -> V<globalstd/core/types/global: H,eitherstd/core/types/either: (V, V) -> V<__w-l28-c31: V,__w-l28-c33: V>> = refstd/core/types/ref: (value : either<() -> $115 $114,$114>) -> <alloc<global>|_133> ref<global,either<() -> $115 $114,$114>>(Leftstd/core/types/Left: forall<a,b> (left : a) -> either<a,b>(actionaction: () -> $115 $114))
+    XDelaystd/core/delayed/XDelay: forall<e,a> (dref : ref<global,either<() -> e a,a>>) -> delayed<e,a>(rr: ref<global,either<() -> $115 $114,$114>>)
+
+// Force a delayed value; the value is computed only on the first
+// call to `force` and cached afterwards.
+pub fun forcestd/core/delayed/force: forall<a,e> (delayed : delayed<e,a>) -> e a( delayeddelayed: delayed<$171,$170> : delayedstd/core/delayed/delayed: (E, V) -> V<ee: E,aa: V> )result: -> 271 270 : ee: E aa: V
+  unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <alloc<global>,div,read<global>,write<global>|$171> $170) -> $171 $170
+    val rr: ref<global,either<() -> $171 $170,$170>> = delayeddelayed: delayed<$171,$170>.drefstd/core/delayed/delayed/dref: (delayed : delayed<$171,$170>) -> <alloc<global>,div,read<global>,write<global>|$171> ref<global,either<() -> $171 $170,$170>>
+    match !std/core/types/ref/(!): (ref : ref<global,either<() -> $171 $170,$170>>) -> <read<global>,div,alloc<_227>,write<global>|$171> either<() -> $171 $170,$170>rr: ref<global,either<() -> $171 $170,$170>>
+      Rightstd/core/types/Right: forall<a,b> (right : b) -> either<a,b>(xx: $170) -> xx: $170
+      Leftstd/core/types/Left: forall<a,b> (left : a) -> either<a,b>(actionaction: () -> $171 $170) ->
+        val xx: $170 = mask-ststd/core/types/mask-st: (() -> <div|$171> $170) -> <alloc<global>,div,read<global>,write<global>|$171> (() -> <st<global>,div|$171> $170){ mask<divstd/core/types/div: X>(actionaction: () -> $171 $170) }()
+        rr: ref<global,either<() -> $171 $170,$170>> :=std/core/types/set: (ref : ref<global,either<() -> $171 $170,$170>>, assigned : either<() -> $171 $170,$170>) -> <write<global>,alloc<global>,div,read<global>|$171> () Rightstd/core/types/Right: forall<a,b> (right : b) -> either<a,b>(xx: $170)
+        xx: $170
+
+// Given a total function to calculate a value `:a`, return
+// a total function that only calculates the value once and then
+// returns the cached result.
+pub fun oncestd/core/delayed/once: forall<a> (calc : () -> a) -> (() -> a)( calccalc: () -> $278 : () -> astd/core/types/total: E )result: -> total () -> 371 : ((std/core/types/total: E) -> astd/core/types/total: E)
+  unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <alloc<_296>|_297> (() -> $278)) -> (() -> $278)
+    val rr: ref<_296,maybe<$278>> = refstd/core/types/ref: (value : maybe<$278>) -> <alloc<_296>|_297> ref<_296,maybe<$278>>(Nothingstd/core/types/Nothing: forall<a> maybe<a>)
+    returnreturn: () -> $278 fnfn: () -> $278()
+      unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <read<_296>,write<_296>,div|_365> $278) -> $278
+        match !std/core/types/ref/(!): (ref : ref<_296,maybe<$278>>) -> <read<_296>,write<_296>,div|_365> maybe<$278>rr: ref<_296,maybe<$278>>
+          Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: $278) -> xx: $278
+          Nothingstd/core/types/Nothing: forall<a> maybe<a> ->
+            val xx: $278 = calccalc: () -> <write<_296>,read<_296>,div|_365> $278()
+            rr: ref<_296,maybe<$278>> :=std/core/types/set: (ref : ref<_296,maybe<$278>>, assigned : maybe<$278>) -> <write<_296>,read<_296>,div|_365> () Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: $278)
+            xx: $278
+
diff --git a/doc/std_core_delayed.html b/doc/std_core_delayed.html index 97fc00b91..d9c388495 100644 --- a/doc/std_core_delayed.html +++ b/doc/std_core_delayed.html @@ -15,7 +15,7 @@ -

std/core/delayed▲toc

+

std/core/delayed▲toc

@@ -26,7 +26,7 @@

Delayed computations.

.

-
+

Delayed (or lazy) values are computed (with effect e) only the first time forcestd/core/delayed/force: forall<a,e> (delayed : delayed<e,a>) -> e a is called and cached afterwards. @@ -44,7 +44,7 @@

Delayed computations. a total function that only calculates the value once and then returns the cached result.

- + diff --git a/doc/std_core_either-source.html b/doc/std_core_either-source.html index 4b9698179..58fd117f7 100644 --- a/doc/std_core_either-source.html +++ b/doc/std_core_either-source.html @@ -10,11 +10,43 @@ - documentation +either.kk documentation -

+
/*---------------------------------------------------------------------------
+  Copyright 2012-2024, Microsoft Research, Daan Leijen.
+
+  This is free software; you can redistribute it and/or modify it under the
+  terms of the Apache License, Version 2.0. A copy of the License can be
+  found in the LICENSE file at the root of this distribution.
+---------------------------------------------------------------------------*/
+
+// Standard `:either` functions.
+module std/core/eitherstd/core/either
+
+import std/core/typesstd/core/types
+import std/core/hndstd/core/hnd
+
+// Convert a `:either` to a `:maybe` type discarding the value of the `Left` constructor
+// and using `Just` for the `Right` constructor.
+pub fun maybestd/core/either/maybe: forall<a,b> (e : either<a,b>) -> maybe<b>( ee: either<$103,$104> : eitherstd/core/types/either: (V, V) -> V<aa: V,bb: V> )result: -> total maybe<132> : maybestd/core/types/maybe: V -> V<bb: V>
+  match ee: either<$103,$104>
+    Leftstd/core/types/Left: forall<a,b> (left : a) -> either<a,b> -> Nothingstd/core/types/Nothing: forall<a> maybe<a>
+    Rightstd/core/types/Right: forall<a,b> (right : b) -> either<a,b>(xx: $104) -> Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: $104)
+
+// Map over the `Right` component of an `:either` type.
+pub fun mapstd/core/either/map: forall<a,b,c,e> (e : either<a,b>, f : (b) -> e c) -> e either<a,c>( ee: either<$43,$44> : eitherstd/core/types/either: (V, V) -> V<aa: V,bb: V>, ff: ($44) -> $46 $45 : bb: V -> ee: E cc: V  )result: -> 90 either<87,89> : ee: E eitherstd/core/types/either: (V, V) -> V<aa: V,cc: V>
+  match ee: either<$43,$44>
+    Rightstd/core/types/Right: forall<a,b> (right : b) -> either<a,b>(xx: $44) -> Rightstd/core/types/Right: forall<a,b> (right : b) -> either<a,b>(ff: ($44) -> $46 $45(xx: $44))
+    Leftstd/core/types/Left: forall<a,b> (left : a) -> either<a,b>(xx: $43)  -> Leftstd/core/types/Left: forall<a,b> (left : a) -> either<a,b>(xx: $43)
+
+// Show an `:either` type
+pub fun showstd/core/either/show: forall<a,b,e> (e : either<a,b>, @implicit/left/show : (a) -> e string, @implicit/right/show : (b) -> e string) -> e string( ee: either<$140,$141> : eitherstd/core/types/either: (V, V) -> V<aa: V,bb: V>, @implicit/left/show?left/show: ($140) -> $142 string : aa: V -> ee: E stringstd/core/types/string: V, @implicit/right/show?right/show: ($141) -> $142 string : bb: V -> ee: E stringstd/core/types/string: V )result: -> 226 string : ee: E stringstd/core/types/string: V
+  match ee: either<$140,$141>
+    Rightstd/core/types/Right: forall<a,b> (right : b) -> either<a,b>(xx: $141) -> "Right("literal: string
count= 6
++std/core/types/(++): (x : string, y : string) -> $142 string xx: $141.show?right/show: ($141) -> $142 string ++std/core/types/(++): (x : string, y : string) -> $142 string ")"literal: string
count= 1
+ Leftstd/core/types/Left: forall<a,b> (left : a) -> either<a,b>(yy: $140) -> "Left("literal: string
count= 5
++std/core/types/(++): (x : string, y : string) -> $142 string yy: $140.show?left/show: ($140) -> $142 string ++std/core/types/(++): (x : string, y : string) -> $142 string ")"literal: string
count= 1
+
diff --git a/doc/std_core_either.html b/doc/std_core_either.html index d98762001..7e5b5ab54 100644 --- a/doc/std_core_either.html +++ b/doc/std_core_either.html @@ -15,30 +15,30 @@ -

std/core/either▲toc

+

std/core/either▲toc

-
+ -
+ -
+ - + diff --git a/doc/std_core_exn-source.html b/doc/std_core_exn-source.html index 4b9698179..ee0b3dbe4 100644 --- a/doc/std_core_exn-source.html +++ b/doc/std_core_exn-source.html @@ -10,11 +10,131 @@ - documentation +exn.kk documentation -

+
/*---------------------------------------------------------------------------
+  Copyright 2012-2024, Microsoft Research, Daan Leijen.
+
+  This is free software; you can redistribute it and/or modify it under the
+  terms of the Apache License, Version 2.0. A copy of the License can be
+  found in the LICENSE file at the root of this distribution.
+---------------------------------------------------------------------------*/
+
+// Standard exception (`:exn`) effect.
+module std/core/exnstd/core/exn
+
+import std/core/typesstd/core/types
+import std/core/hndstd/core/hnd
+
+extern import
+  c  file "inline/exn"
+  js file "inline/exn.js"
+
+
+// Exceptions
+pubstd/core/exn/exn: (E, V) -> V effect exnstd/core/exn/exn: (E, V) -> V
+  // Throw an exception
+  final ctl throw-exn( exnexn: exception : exceptionstd/core/exn/exception: V ) : aa: V
+
+// Raise a pattern match exception. This is function is used internally by the
+// compiler to generate error messages on pattern match failures.
+pub fun error-patternstd/core/exn/error-pattern: forall<a> (location : string, definition : string) -> exn a(locationlocation: string : stringstd/core/types/string: V, definitiondefinition: string : stringstd/core/types/string: V)result: -> exn 820 : exnstd/core/exn/exn: (E, V) -> V aa: V
+  throwstd/core/exn/throw: (message : string, info : ? exception-info) -> exn $764(locationlocation: string ++std/core/types/(++): (x : string, y : string) -> exn string ": "literal: string
count= 2
++std/core/types/(++): (x : string, y : string) -> exn string definitiondefinition: string ++std/core/types/(++): (x : string, y : string) -> exn string ": pattern match failure"literal: string
count= 23
, + ExnPatternstd/core/exn/ExnPattern: (location : string, definition : string) -> exception-info(locationlocation: string,definitiondefinition: string)
) + +// The exception data type +pub value struct exceptionstd/core/exn/exception: V( messagestd/core/exn/exception/message: (exception : exception) -> string :stringstd/core/types/string: V, infostd/core/exn/exception/info: (exception : exception) -> exception-info :exception-infostd/core/exn/exception-info: V ) + +// Exception information +pub open type exception-infostd/core/exn/exception-info: V + ExnErrorstd/core/exn/ExnError: exception-info // Generic error + ExnAssertstd/core/exn/ExnAssert: exception-info + ExnTodostd/core/exn/ExnTodo: exception-info + ExnRangestd/core/exn/ExnRange: exception-info + ExnPatternstd/core/exn/ExnPattern: (location : string, definition : string) -> exception-info( location : stringstd/core/types/string: V, definition : stringstd/core/types/string: V ) + ExnSystemstd/core/exn/ExnSystem: (errno : int) -> exception-info( errno : intstd/core/types/int: V ) + ExnInternalstd/core/exn/ExnInternal: (name : string) -> exception-info( name : stringstd/core/types/string: V ) + +// Show the exception message +pub fun showstd/core/exn/show: (exn : exception) -> string( exnexn: exception : exceptionstd/core/exn/exception: V )result: -> total string : stringstd/core/types/string: V + exnexn: exception.messagestd/core/exn/exception/message: (exception : exception) -> string + +// Throw an exception with a specified message. +pub fun throwstd/core/exn/throw: forall<a> (message : string, info : ? exception-info) -> exn a( messagemessage: string: stringstd/core/types/string: V, infoinfo: ? exception-info : exception-infostd/core/exn/exception-info: V = ExnErrorstd/core/exn/ExnError: exception-info )result: -> exn 759 : exnstd/core/exn/exn: (E, V) -> V aa: V + throw-exnstd/core/exn/throw-exn: (exn : exception) -> exn $739(Exceptionstd/core/exn/Exception: (message : string, info : exception-info) -> exception(messagemessage: string,infoinfo: exception-info)) + +// Catch any exception raised in `action` and handle it. +// Use `on-exn` or `on-exit` when appropriate. +pub fun exn/trystd/core/exn/exn/try: forall<a,e> (action : () -> <exn|e> a, hndl : (exception) -> e a) -> e a( actionaction: () -> <exn|$587> $586 : () -> <exnstd/core/exn/exn: (E, V) -> V|std/core/types/effect-extend: (X, E) -> Eee: E> aa: V, hndlhndl: (exception) -> $587 $586: exceptionstd/core/exn/exception: V -> ee: E aa: V )result: -> 662 661 : ee: E aa: V + withhandler: (() -> <exn|$587> $586) -> $587 $586 final ctl throw-exnthrow-exn: (exn : exception) -> $587 $586(exnexn: exception) hndlhndl: (exception) -> $587 $586(exnexn: exception) + actionaction: () -> <exn|$587> $586() + +// _Deprecated_; use `try` instead. Catch an exception raised by `throw` and handle it. +// Use `on-exn` or `on-exit` when appropriate. +pub fun catchstd/core/exn/catch: forall<a,e> (action : () -> <exn|e> a, hndl : (exception) -> e a) -> e a( actionaction: () -> <exn|$714> $713 : () -> <exnstd/core/exn/exn: (E, V) -> V|std/core/types/effect-extend: (X, E) -> Eee: E> aa: V, hndlhndl: (exception) -> $714 $713: exceptionstd/core/exn/exception: V -> ee: E aa: V)result: -> 732 731 : ee: E aa: V + trystd/core/exn/exn/try: (action : () -> <exn|$714> $713, hndl : (exception) -> $714 $713) -> $714 $713(actionaction: () -> <exn|$714> $713,hndlhndl: (exception) -> $714 $713) + +// An `:error` type represents a first-class exception result. +pub value type errorstd/core/exn/error: V -> V<aa: V> + Errorstd/core/exn/Error: forall<a> (exception : exception) -> error<a>( exception : exceptionstd/core/exn/exception: V ) + Okstd/core/exn/Ok: forall<a> (result : a) -> error<a>( result : aa: V ) + +// Transform an exception effect to an `:error` type. +pub fun trystd/core/exn/try: forall<a,e> (action : () -> <exn|e> a) -> e error<a>( actionaction: () -> <exn|$670> $669 : () -> <exnstd/core/exn/exn: (E, V) -> V|std/core/types/effect-extend: (X, E) -> Eee: E> aa: V )result: -> 702 error<701> : ee: E errorstd/core/exn/error: V -> V<aa: V> + trystd/core/exn/exn/try: (action : () -> <exn|$670> error<$669>, hndl : (exception) -> $670 error<$669>) -> $670 error<$669>({ Okstd/core/exn/Ok: forall<a> (result : a) -> error<a>(actionaction: () -> <exn|$670> $669()) }, fnfn: (exn : exception) -> $670 error<$669>(exnexn: exception){ Errorstd/core/exn/Error: forall<a> (exception : exception) -> error<a>(exnexn: exception) }) + +// Transform an `:error` type back to an `exn` effect. +pub fun untrystd/core/exn/untry: forall<a> (err : error<a>) -> exn a( errerr: error<$825> : errorstd/core/exn/error: V -> V<aa: V> )result: -> exn 846 : exnstd/core/exn/exn: (E, V) -> V aa: V + match errerr: error<$825> + Errorstd/core/exn/Error: forall<a> (exception : exception) -> error<a>(exnexn: exception) -> throw-exnstd/core/exn/throw-exn: (exn : exception) -> exn $825(exnexn: exception) + Okstd/core/exn/Ok: forall<a> (result : a) -> error<a>(xx: $825) -> xx: $825 + +// Transform an `:error` type back to an `exn` effect. +pub fun exnstd/core/exn/exn: forall<a> (err : error<a>) -> exn a( errerr: error<$851> : errorstd/core/exn/error: V -> V<aa: V> )result: -> exn 863 : exnstd/core/exn/exn: (E, V) -> V aa: V + untrystd/core/exn/untry: (err : error<$851>) -> exn $851(errerr: error<$851>) + +// Use default value `def` in case of an error. +pub fun defaultstd/core/exn/default: forall<a> (t : error<a>, def : a) -> a( tt: error<$416> : errorstd/core/exn/error: V -> V<aa: V>, defdef: $416 : aa: V )result: -> total 431 : astd/core/types/total: E + match tt: error<$416> + Errorstd/core/exn/Error: forall<a> (exception : exception) -> error<a> -> defdef: $416 + Okstd/core/exn/Ok: forall<a> (result : a) -> error<a>(xx: $416) -> xx: $416 + +// Transform an `:error` type to a `:maybe` value. +pub fun maybestd/core/exn/maybe: forall<a> (t : error<a>) -> maybe<a>( tt: error<$474> : errorstd/core/exn/error: V -> V<aa: V> )result: -> total maybe<497> : maybestd/core/types/maybe: V -> V<aa: V> + match tt: error<$474> + Errorstd/core/exn/Error: forall<a> (exception : exception) -> error<a> -> Nothingstd/core/types/Nothing: forall<a> maybe<a> + Okstd/core/exn/Ok: forall<a> (result : a) -> error<a>(xx: $474) -> Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: $474) + +// Transform an `:error` type to an `:either` value. +pub fun eitherstd/core/exn/either: forall<a> (t : error<a>) -> either<exception,a>( tt: error<$436> : errorstd/core/exn/error: V -> V<aa: V> )result: -> total either<exception,469> : eitherstd/core/types/either: (V, V) -> V<exceptionstd/core/exn/exception: V,aa: V> + match tt: error<$436> + Errorstd/core/exn/Error: forall<a> (exception : exception) -> error<a>(exnexn: exception) -> Leftstd/core/types/Left: forall<a,b> (left : a) -> either<a,b>(exnexn: exception) + Okstd/core/exn/Ok: forall<a> (result : a) -> error<a>(xx: $436) -> Rightstd/core/types/Right: forall<a,b> (right : b) -> either<a,b>(xx: $436) + +/* +// Set a `hndler` that is called only when an exception is raised in the `action` block. +pub fun on-exn( hndler : exception -> <exn|e> (), action : () -> <exn|e> a ) : <exn|e> a + // prim-try-some( action, fn(exn){ hndler(exn); throw(exn) }) + match mask<exn>{ try(action) } + TryOk(x) { x + TryExn(exn) { hndler(exn); throw(exn) +*/ + +// Set a `hndler` that is always called when the `action` finishes (either normally or with an exception). +pub fun on-exitstd/core/exn/on-exit: forall<a,e> (hndler : () -> e (), action : () -> e a) -> e a( hndlerhndler: () -> $503 () : () -> ee: E (std/core/types/unit: V)std/core/types/unit: V, actionaction: () -> $503 $502 : () -> ee: E aa: V )result: -> 519 518 : ee: E aa: V + finallystd/core/hnd/finally: (fin : () -> $503 (), action : () -> $503 $502) -> $503 $502(hndlerhndler: () -> $503 (),actionaction: () -> $503 $502) + +pub fun exn-error-rangestd/core/exn/exn-error-range: forall<a> () -> exn a()result: -> exn 887 : exnstd/core/exn/exn: (E, V) -> V aa: V + throwstd/core/exn/throw: (message : string, info : ? exception-info) -> exn $868("index out-of-range"literal: string
count= 18
, ExnRangestd/core/exn/ExnRange: exception-info
) + + +// // _Unsafe_. This function removes the exception effect (`:exn`) from the effect of an action +// pub fun unsafe-no-exn( action : () -> <exn|e> a ) : e a +// unsafe-total( action ) + +
diff --git a/doc/std_core_exn.html b/doc/std_core_exn.html index 10395f4af..43a33a199 100644 --- a/doc/std_core_exn.html +++ b/doc/std_core_exn.html @@ -15,7 +15,7 @@ -

std/core/exn▲toc

+

std/core/exn▲toc

-
+

An errorstd/core/exn/error: V -> V type represents a first-class exception result.

con Ok(result : a)
fun default( t : errorstd/core/exn/error: V -> V<a>, def : a ) : a

Use default value def in case of an error. -

Transform an exception effect to an errorstd/core/exn/error: V -> V type. @@ -54,16 +54,16 @@

Standard exception (Transform an errorstd/core/exn/error: V -> V type back to an exnstd/core/exn/exn: forall<a> (err : error<a>) -> exn a effect.

-
+ -
+

Exception information.

Generic error. -

con ExnTodo
con ExnTodo
-
+ -
+

Raise a pattern match exception. This is function is used internally by the compiler to generate error messages on pattern match failures. @@ -133,11 +133,11 @@

Standard exception (Set a hndler that is always called when the action finishes (either normally or with an exception).

-
+

Throw an exception with a specified message.

- + diff --git a/doc/std_core_hnd-source.html b/doc/std_core_hnd-source.html index 4b9698179..62348fd99 100644 --- a/doc/std_core_hnd-source.html +++ b/doc/std_core_hnd-source.html @@ -10,11 +10,934 @@ - documentation +hnd.kk documentation -

+
/*---------------------------------------------------------------------------
+  Copyright 2012-2024, Microsoft Research, Daan Leijen.
+
+  This is free software; you can redistribute it and/or modify it under the
+  terms of the Apache License, Version 2.0. A copy of the License can be
+  found in the LICENSE file at the root of this distribution.
+---------------------------------------------------------------------------*/
+
+/* Internal effect handler primitives.
+ 
+  Internal primitives to implement evidence based algebraic
+  effect handlers. These are emitted by the compiler during evidence
+  translation and this module is always implicitly imported.
+
+  This module is compiled _without monadic translation_ and
+  thus we need to do this by hand in this module which allows us to implement
+  most primitives directly in Koka keeping the external C/JavaScript/etc primitives
+  to a minimum.
+
+  The paper:
+
+  > Ningning Xie, and Daan Leijen. _Generalized Evidence Passing for Effect Handlers_,
+  > or _efficient compilation of effect handlers to C_.
+  > Proceedings of the ACM International Conference on Functional Programming (ICFP'21),
+  > August 2021, Vol 5: pp. 71, doi: 10.1145/3473576.
+  > <https://www.microsoft.com/en-us/research/publication/generalized-evidence-passing-for-effect-handlers-or-efficient-compilation-of-effect-handlers-to-c/>
+
+  describes precisely how the monadic evidence translation works on which this
+  module is based. Read this first to understand how this module works.
+
+  Another paper of interest is:
+
+  > Ningning Xie, and Daan Leijen. _Effect Handlers in Haskell, Evidently_.
+  > The 13th ACM SIGPLAN International Haskell Symposium, (Haskell'20),
+  > August 2020. <https://www.microsoft.com/en-us/research/uploads/prod/2020/07/effev.pdf>
+
+  which which explains the internal typing of handlers, evidence vectors, etc. in a simpler setting.
+
+  ## Notes
+
+  An effect _row_ has kind `::E`, while an atomic effect kind is `::X`.
+  (We will see that `::X` is equal to the kind `::(E,V) -> V` ) (`::V` is for value kinds *)
+
+  We use the term "answer" context to talk about the result type `:r` and effect type `:e` of
+  (the context of) the handler in the stack. The `:e` does not include the effect `::X` of the handler.
+
+  - `:marker<e,r>` : a unique integer corresponding to an answer context `:<e,r>`. This functions
+    as a dependent type: when the integer matches at runtime, that will be the type of the answer context.
+
+  - handlers `:h` are partially applied types with signature `h<e,r> :: (E,V)->V`
+    for some answer context `:<e,r>`. The handlers contain all operations (much like a virtual method table).
+    (these handler types are generated by the compiler for each effect type)
+
+  - Evidence `ev<h :: (E,V)->V >` for a handler `:h` is an existential tuple
+    `forall e r. Ev( marker: marker<e,r>, hnd: h<e,r> )` containing the marker and the actual handler (pointer)
+    for some answer context `:<e,r>` -- we don't know the answer context exact type as it depends on where
+    the handler was dynamically bound; we just have evidence that this handler `:h` exists in our context.
+
+  - Actually, we use a quadruple for the evidence (corresponding to the evidence as formalized in the generalized evidence paper).
+    We also add the handler effect tag (`:htag<h>`) (for dynamic lookup), and the evidence vector
+    of the answer context where the handler was defind (`:evv<e,r>`)
+    (so we can execute operations in-place using the evidence vector at the point where they were defined).
+
+  - Each operation definition in a handler is called a _clause_. For a one argument operation, we have:
+    ```
+    abstract value type clause1<a,b,h,e::E,r>
+      Clause1( clause: (marker<e,r>, ev<h>, a) -> e b )
+    ```
+    defining an operation `:a -> b` for some handler `:h` in an answer context `:<e,r>`.
+    (these are generated by the compiler from a handler definition)
+
+  - An operation is performed by a rank-2 function:
+    `fun perform1( ev : ev<h>, select-op : (forall<e1,r> h<e1,r> -> clause1<a,b,h,e1,r>), x : a ) : e b`
+    where we can call an operation given evidence for a handler `:ev<h>` together with a
+    polymorphic field selection function that for any handler `h` in _any_ answer context, returns its clause.
+    It is defined as:
+    ```
+      match ev
+        Ev(_tag,m,h,_answ) -> match select-op(h)  // for an abstract `:<e1,r>`
+          Clause1(f) -> f(m,ev,x)
+    ```
+
+  - Each clause _definition_ can now determine to fully yield to the handler, or be tail-resumptive etc.
+    (that is, this is determined at the handler definition site, not the call site, and generated by the compiler)
+    For example, we could be most general (`ctl`) and yield back to the marker (where the handler was defined in the call-stack)
+    (with a function that receives the continuation/resumption `k`):
+    ```
+    Clause1( fn(m,ev,x) yield-to(m, fn(k) op(k,x) ))
+    ```
+    or be super efficient and directly call the (tail-resumptive) operation in-place (`fun`):
+    ```
+    Clause1( fn(m,ev,x) op(x) )
+    ```
+    and various variants in-between. The last definition is unsafe for example if the (user defined) `op` invokes
+    operations itself as the evidence vector should be the one as defined at the handler site.
+    So, we norally use instead:
+    ```
+    Clause1( fn(m,ev,x) under1(ev,op,x) )
+    ```
+    where `under1` uses the evidence vector (`hevv`) stored in the evidence `ev` to execute `op(x)` under.
+    (this is also explained in detail in the generalized evidence paper).
+
+*/
+module std/core/hndstd/core/hnd
+
+import std/core/typesstd/core/types
+import std/core/undivstd/core/undiv
+
+extern import
+  c  file "inline/hnd"
+  js file "inline/hnd.js"
+
+// -------------------------------------------
+// Internal types
+// -------------------------------------------
+
+// The tag of a handler identifies the type at runtime (e.g. `"exn/core/std"`).
+abstract value type htagstd/core/hnd/htag: ((E, V) -> V) -> V<hh: (E, V) -> V::(E,V)->V>
+  Htagstd/core/hnd/Htag: forall<a> (tagname : string) -> htag<a>(tagnamestd/core/hnd/htag/tagname: forall<a> (htag : htag<a>) -> string:stringstd/core/types/string: V)
+
+// _Internal_ hidden constructor for creating handler tags
+pub fun @new-htag( tagtag: string : stringstd/core/types/string: V )result: -> total htag<2703> : htagstd/core/hnd/htag: ((E, V) -> V) -> V<hh: (E, V) -> V>
+  Htagstd/core/hnd/Htag: forall<a> (tagname : string) -> htag<a>(tagtag: string)
+
+// Show a handler tag.
+pub fun htag/showstd/core/hnd/htag/show: forall<a> (htag<a>) -> string( Htagstd/core/hnd/Htag: forall<a> (tagname : string) -> htag<a>(tagtag: string) : htagstd/core/hnd/htag: ((E, V) -> V) -> V<hh: (E, V) -> V> )result: -> total string : stringstd/core/types/string: V
+  tagtag: string
+
+
+// Effect handler evidence of a handler `:h` in the context.
+abstract type evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>
+  con Evstd/core/hnd/Ev: forall<a,e,b> (htag : htag<a>, marker : marker<e,b>, hnd : a<e,b>, hevv : evv<e>) -> ev<a><ee: E,rr: V>(htagstd/core/hnd/ev/htag: forall<a> (ev : ev<a>) -> htag<a>:htagstd/core/hnd/htag: ((E, V) -> V) -> V<hh: (E, V) -> V>, marker:markerstd/core/hnd/marker: (E, V) -> V<ee: E,rr: V>, hnd:hh: (E, V) -> V<ee: E,rr: V>, hevv:evvstd/core/hnd/evv: E -> V<ee: E>)
+
+// Abstract type of Evidence vectors
+type evvstd/core/hnd/evv: E -> V<ee: E::E>
+
+// Index into an evidence vector
+pub alias ev-indexstd/core/hnd/ev-index: V = ssize_tstd/core/types/ssize_t: V
+
+// Evidence equality compares the markers.
+pub fun ev/(==)std/core/hnd/ev/(==): forall<a> (ev<a>, ev<a>) -> bool( Evstd/core/hnd/Ev: forall<a,e,b> (htag : htag<a>, marker : marker<e,b>, hnd : a<e,b>, hevv : evv<e>) -> ev<a>(_,m1m1: marker<$10257,$10258>)  : evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>, Evstd/core/hnd/Ev: forall<a,e,b> (htag : htag<a>, marker : marker<e,b>, hnd : a<e,b>, hevv : evv<e>) -> ev<a>(_,m2m2: marker<$10267,$10268>) : evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V> )result: -> total bool : boolstd/core/types/bool: V
+  eq-markerstd/core/hnd/eq-marker: (x : marker<$10257,$10258>, y : marker<$10267,$10268>) -> bool(m1m1: marker<$10257,$10258>,m2m2: marker<$10267,$10268>)
+
+
+// -------------------------------------------
+// Internal Markers
+// -------------------------------------------
+
+// _Internal_. The type of handler markers (usually `:int32_t`).
+// Needed for effect handlers in `module std/core/hnd`.
+value type markerstd/core/hnd/marker: (E, V) -> V<ee: E::E,aa: V>
+
+// Are two markers equal?
+extern eq-markerstd/core/hnd/eq-marker: forall<a,b,e,e1> (x : marker<e,a>, y : marker<e1,b>) -> bool( xx: marker<$4031,$4029> : markerstd/core/hnd/marker: (E, V) -> V<e1e1: E,a1a1: V>, yy: marker<$4032,$4030> : markerstd/core/hnd/marker: (E, V) -> V<e2e2: E,a2a2: V> ) : boolstd/core/types/bool: V
+  inline "#1==#2"
+
+extern fresh-markerstd/core/hnd/fresh-marker: forall<a,e> () -> marker<e,a>() : markerstd/core/hnd/marker: (E, V) -> V<ee: E,aa: V>
+  c inline "kk_marker_unique(kk_context())"
+  js inline "$marker_unique++"
+
+extern fresh-marker-namedstd/core/hnd/fresh-marker-named: forall<a,e> () -> marker<e,a>() : markerstd/core/hnd/marker: (E, V) -> V<ee: E,aa: V>
+  c inline  "-kk_marker_unique(kk_context())"
+  js inline "-($marker_unique++)"
+
+
+
+// -------------------------------------------
+// Internal Evidence vectors
+// The datatype is `:evv<e>` is internal for performance
+// reasons and since different backends may have different
+// requirements.
+// -------------------------------------------
+
+// Insert new evidence into the given evidence vector.
+extern evv-insertstd/core/hnd/evv-insert: forall<e,e1,a> (evv : evv<e>, ev : ev<a>) -> e evv<e1>( evvevv: evv<$3325> : evvstd/core/hnd/evv: E -> V<e1e1: E>, evev: ev<$3327> : evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V> ) : e1e1: E evvstd/core/hnd/evv: E -> V<e2e2: E>
+  c  "kk_evv_insert"
+  js "_evv_insert"
+
+// show evidence for debug purposes
+extern evv-showstd/core/hnd/evv-show: forall<e> (evv : evv<e>) -> string( evvevv: evv<$4077> : evvstd/core/hnd/evv: E -> V<ee: E> ) : stringstd/core/types/string: V
+  c  "kk_evv_show"
+  js "_evv_show"
+
+// Is an evidence vector unchanged? (i.e. as pointer equality).
+// This is used to avoid copying in common cases.
+extern evv-eqstd/core/hnd/evv-eq: forall<e> (evv0 : evv<e>, evv1 : evv<e>) -> bool(evv0evv0: evv<$3385> : evvstd/core/hnd/evv: E -> V<ee: E>, evv1evv1: evv<$3385> : evvstd/core/hnd/evv: E -> V<ee: E> ) : boolstd/core/types/bool: V
+  c  "kk_evv_eq"
+  js inline "(#1) === (#2)"
+
+
+// -------------------------------------------
+// Operations on the "current" evidence vector
+// -------------------------------------------
+
+// Return the evidence at index `i` in the current evidence vector.
+pub inline extern @evv-at<e,h> ( i : ev-indexstd/core/hnd/ev-index: V ) : evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>  // pretend total; don't simplify
+  c  "kk_evv_at"
+  js "$std_core_hnd._evv_at"
+
+// (dynamically) find evidence insertion/deletion index in the evidence vector
+// The compiler optimizes `@evv-index` to a static index when apparent from the effect type.
+pub extern @evv-index<ee: E::E,hh: (E, V) -> V>( htaghtag: htag<$2628> : htagstd/core/hnd/htag: ((E, V) -> V) -> V<hh: (E, V) -> V> ) : ee: E ev-indexstd/core/hnd/ev-index: V
+  c  "kk_evv_index"
+  js "__evv_index"
+
+// Get the current evidence vector.
+extern evv-getstd/core/hnd/evv-get: forall<e> () -> e evv<e>() : ee: E evvstd/core/hnd/evv: E -> V<ee: E>
+  c  "kk_evv_get"
+  js "$std_core_hnd._evv_get"
+
+// Set the current evidence vector.
+inline extern evv-setstd/core/hnd/evv-set: forall<e,e1> (w : evv<e1>) -> e ()<e1,e>( w : evvstd/core/hnd/evv: E -> V<e1e1: E> ) : ee: E (std/core/types/unit: V)std/core/types/unit: V
+  c  "kk_evv_set"
+  js "$std_core_hnd._evv_set"
+
+// Does the current evidence vector consist solely of affine handlers?
+// This is called in backends that do not have context paths (like javascript)
+// to optimize TRMC (where we can use faster update-in-place TRMC if we know the
+// operations are all affine). As such, it is always safe to return `false`.
+//
+// control flow context:
+//                 -1: none: bottom
+//                   /          \
+// 0: except: never resumes   1: linear: resumes exactly once
+//                   \          /
+//           2: affine: resumes never or once
+//                        |
+//     3: multi: resumes never, once, or multiple times
+//
+pub extern @evv-is-affine() : boolstd/core/types/bool: V
+  c  inline "kk_evv_is_affine(kk_context())"
+  js inline "$std_core_hnd._evv_is_affine_()"
+
+
+// -----------------------------------------------------------------------------------
+// Various swap variants.
+// These are here just for improved performance (by avoiding dup/drop for example)
+// -----------------------------------------------------------------------------------
+
+// Swap the current evidence vector with `w`
+inline extern evv-swapstd/core/hnd/evv-swap: forall<e,e1,e2> (w : evv<e1>) -> e evv<e2><e1,e2>( w : evvstd/core/hnd/evv: E -> V<e1e1: E> ) : ee: E evvstd/core/hnd/evv: E -> V<e2e2: E>
+  c  "kk_evv_swap"
+  js "$std_core_hnd._evv_swap"
+
+// Remove evidence at index `i` of the current evidence vector, and return the old one.
+// (used by `mask`)
+extern evv-swap-deletestd/core/hnd/evv-swap-delete: forall<e,e1> (i : ev-index, behind : bool) -> e1 evv<e>( ii: ev-index : ev-indexstd/core/hnd/ev-index: V, behindbehind: bool : boolstd/core/types/bool: V ) : e1e1: E evvstd/core/hnd/evv: E -> V<ee: E>
+  c  "kk_evv_swap_delete"
+  js "_evv_swap_delete"
+
+// Swap the current evidence vector with an empty vector.
+// (this is used in open calls to switch to a total context)
+inline extern evv-swap-create0std/core/hnd/evv-swap-create0: forall<e> () -> e evv<e>() : ee: E evvstd/core/hnd/evv: E -> V<ee: E>  //not quite the right effect type but avoids unbound effect types
+  c  "kk_evv_swap_create0"
+  js "$std_core_hnd._evv_swap_create0"
+
+// Swap the current evidence vector with a singleton vector (with the evidence at current index `i`).
+// (this is common in open calls to switch to a singleton effect context when calling operations)
+inline extern evv-swap-create1std/core/hnd/evv-swap-create1: forall<e> (i : ev-index) -> e evv<e>( i : ev-indexstd/core/hnd/ev-index: V ) : ee: E evvstd/core/hnd/evv: E -> V<ee: E>  //not quite the right effect type but avoids unbound effect types
+  c  "kk_evv_swap_create1"
+  js "$std_core_hnd._evv_swap_create1"
+
+// Swap the current evidence vector with a new vector consisting of evidence
+// at indices `indices` in the current vector.
+extern evv-swap-createstd/core/hnd/evv-swap-create: forall<e> (indices : vector<ev-index>) -> e evv<e>( indicesindices: vector<ev-index> : vectorstd/core/types/vector: V -> V<ev-indexstd/core/hnd/ev-index: V> ) : ee: E evvstd/core/hnd/evv: E -> V<ee: E>  //not quite the right effect type but avoids unbound effect types
+  c  "kk_evv_swap_create"
+  js "_evv_swap_create"
+
+
+
+// -------------------------------------------
+// Internal multi-prompt delimited control
+// -------------------------------------------
+
+pub inline extern yieldingstd/core/hnd/yielding: () -> bool() : boolstd/core/types/bool: V
+  c  "kk_yielding"
+  js "$std_core_hnd._yielding"
+
+pub inline extern yielding-non-finalstd/core/hnd/yielding-non-final: () -> bool() : boolstd/core/types/bool: V
+  c  "kk_yielding_non_final"
+  js "$std_core_hnd._yielding_non_final"
+
+pub noinline extern yield-extendstd/core/hnd/yield-extend: forall<a,b,e> (next : (a) -> e b) -> e b(nextnext: ($3416) -> $3418 $3417 : aa: V -> ee: E bb: V ) : ee: E bb: V
+  c  "kk_yield_extend"
+  js "_yield_extend"
+
+pub inline fun yield-bindstd/core/hnd/yield-bind: forall<a,b,e> (x : a, next : (a) -> e b) -> e b( xx: $4318 : aa: V, nextnext: ($4318) -> $4320 $4319 : aa: V -> ee: E bb: V )result: -> 4349 4348 : ee: E bb: V
+  if yieldingstd/core/hnd/yielding: () -> $4320 bool() then yield-extendstd/core/hnd/yield-extend: (next : ($4318) -> $4320 $4319) -> $4320 $4319(nextnext: ($4318) -> $4320 $4319) else nextnext: ($4318) -> $4320 $4319(xx: $4318)
+
+pub inline fun yield-bind2std/core/hnd/yield-bind2: forall<a,b,e> (x : a, extend : (a) -> e b, next : (a) -> e b) -> e b( xx: $10213 : aa: V, extendextend: ($10213) -> $10215 $10214 : aa: V -> ee: E bb: V, nextnext: ($10213) -> $10215 $10214 : aa: V -> ee: E bb: V )result: -> 10244 10243 : ee: E bb: V
+  if yieldingstd/core/hnd/yielding: () -> $10215 bool() then yield-extendstd/core/hnd/yield-extend: (next : ($10213) -> $10215 $10214) -> $10215 $10214(extendextend: ($10213) -> $10215 $10214) else nextnext: ($10213) -> $10215 $10214(xx: $10213)
+
+extern yield-contstd/core/hnd/yield-cont: forall<a,e,b> (f : forall<c> ((c) -> e a, c) -> e b) -> e b(ff: forall<a> ((a) -> $3450 $3449, a) -> $3450 $3451 : forall<bb: V> (bb: V -> ee: E aa: V, bb: V) -> ee: E rr: V ) : ee: E rr: V  // make hidden pub?
+  c  "kk_yield_cont"
+  js "_yield_cont"
+
+inline extern keep-yielding-finalstd/core/hnd/keep-yielding-final: forall<e,a> () -> e a() : ee: E rr: V
+  c  "kk_box_any"
+  js inline "undefined"
+
+extern yield-promptstd/core/hnd/yield-prompt: forall<a,e,b> (m : marker<e,b>) -> yld<e,a,b>( mm: marker<$3492,$3493>: markerstd/core/hnd/marker: (E, V) -> V<ee: E,rr: V> ) : yldstd/core/hnd/yld: (E, V, V) -> V<ee: E,aa: V,rr: V>
+  c  "kk_yield_prompt"
+  js "_yield_prompt"
+
+extern yield-to-primstd/core/hnd/yield-to-prim: forall<a,e,e1,b> (m : marker<e1,b>, clause : ((resume-result<a,b>) -> e1 b) -> e1 b) -> e (() -> a)( mm: marker<$3722,$3723> : markerstd/core/hnd/marker: (E, V) -> V<e1e1: E,rr: V>, clauseclause: ((resume-result<$3720,$3723>) -> $3722 $3723) -> $3722 $3723 : (resume-resultstd/core/hnd/resume-result: (V, V) -> V<bb: V,rr: V> -> e1e1: E rr: V) -> e1e1: E rr: V ) : ee: E (() -> bstd/core/types/total: E)
+  c  "kk_yield_to"
+  js "$std_core_hnd._yield_to"
+
+extern yield-to-finalstd/core/hnd/yield-to-final: forall<a,e,e1,b> (m : marker<e1,b>, clause : ((resume-result<a,b>) -> e1 b) -> e1 b) -> e a( mm: marker<$3530,$3531> : markerstd/core/hnd/marker: (E, V) -> V<e1e1: E,rr: V>, clauseclause: ((resume-result<$3528,$3531>) -> $3530 $3531) -> $3530 $3531 : (resume-resultstd/core/hnd/resume-result: (V, V) -> V<bb: V,rr: V> -> e1e1: E rr: V) -> e1e1: E rr: V ) : ee: E bb: V
+  c  "kk_yield_final"
+  js "$std_core_hnd._yield_final"
+
+noinline fun yield-tostd/core/hnd/yield-to: forall<a,e,b> (m : marker<e,b>, clause : ((resume-result<a,b>) -> e b) -> e b) -> e a( mm: marker<$6674,$6675> : markerstd/core/hnd/marker: (E, V) -> V<e1e1: E,rr: V>, clauseclause: ((resume-result<$6673,$6675>) -> $6674 $6675) -> $6674 $6675 : (resume-resultstd/core/hnd/resume-result: (V, V) -> V<bb: V,rr: V> -> e1e1: E rr: V) -> e1e1: E rr: V )result: -> 6716 6715 : e1e1: E bb: V
+  //val w0 = evv-get()
+  val gg: () -> $6673 : () -> _b_b: V = yield-to-primstd/core/hnd/yield-to-prim: (m : marker<$6674,$6675>, clause : ((resume-result<$6673,$6675>) -> $6674 $6675) -> $6674 $6675) -> $6674 (() -> $6673)(mm: marker<$6674,$6675>, clauseclause: ((resume-result<$6673,$6675>) -> $6674 $6675) -> $6674 $6675)
+  yield-extendstd/core/hnd/yield-extend: (next : (() -> $6674 $6673) -> $6674 $6673) -> $6674 $6673 fnfn: (f : () -> $6674 $6673) -> $6674 $6673(ff: () -> $6674 $6673)
+    // val keep1 = guard(w0)  // check the evidence is correctly restored
+    ff: () -> $6674 $6673()
+
+pub type yield-infostd/core/hnd/yield-info: V
+
+extern yield-capturestd/core/hnd/yield-capture: forall<e> () -> e yield-info() : ee: E yield-infostd/core/hnd/yield-info: V
+  c "kk_yield_capture"
+  js "_yield_capture"
+
+pub extern unsafe-reyieldstd/core/hnd/unsafe-reyield: forall<a,e> (yld : yield-info) -> e a(yldyld: yield-info : yield-infostd/core/hnd/yield-info: V) : ee: E aa: V
+  c "kk_yield_reyield"
+  js "_reyield"
+
+
+// -------------------------------------------
+//
+// -------------------------------------------
+
+inline extern cast-ev0std/core/hnd/cast-ev0: forall<a,e,e1> (f : () -> e1 a) -> (() -> e a)( f:() -> e1e1: E bb: V) : ((std/core/types/total: E) -> e0e0: E bb: V)
+  inline "#1"
+
+inline extern cast-ev1std/core/hnd/cast-ev1: forall<a,b,e,e1> (f : (a) -> e1 b) -> ((a) -> e b)( f:(a1a1: V) -> e1e1: E bb: V) : ((std/core/types/total: Ea1a1: V) -> e0e0: E bb: V)
+  inline "#1"
+
+inline extern cast-ev2std/core/hnd/cast-ev2: forall<a,b,c,e,e1> (f : (a, b) -> e1 c) -> ((a, b) -> e c)( f:(a1a1: V,a2a2: V) -> e1e1: E bb: V) : ((std/core/types/total: Ea1a1: V,a2a2: V) -> e0e0: E bb: V)
+  inline "#1"
+
+inline extern cast-ev3std/core/hnd/cast-ev3: forall<a,b,c,d,e,e1> (f : (a, b, c) -> e1 d) -> ((a, b, c) -> e d)( f:(a1a1: V,a2a2: V,a3a3: V) -> e1e1: E bb: V) : ((std/core/types/total: Ea1a1: V,a2a2: V,a3a3: V) -> e0e0: E bb: V)
+  inline "#1"
+
+inline extern cast-ev4std/core/hnd/cast-ev4: forall<a,b,c,d,a1,e,e1> (f : (a, b, c, d) -> e1 a1) -> ((a, b, c, d) -> e a1)( f:(a1a1: V,a2a2: V,a3a3: V,a4a4: V) -> e1e1: E bb: V) : ((std/core/types/total: Ea1a1: V,a2a2: V,a3a3: V,a4a4: V) -> e0e0: E bb: V)
+  inline "#1"
+
+inline extern cast-ev5std/core/hnd/cast-ev5: forall<a,b,c,d,a1,b1,e,e1> (f : (a, b, c, d, a1) -> e1 b1) -> ((a, b, c, d, a1) -> e b1)( f:(a1a1: V,a2a2: V,a3a3: V,a4a4: V,a5a5: V) -> e1e1: E bb: V) : ((std/core/types/total: Ea1a1: V,a2a2: V,a3a3: V,a4a4: V,a5a5: V) -> e0e0: E bb: V)
+  inline "#1"
+
+value type resume-resultstd/core/hnd/resume-result: (V, V) -> V<bb: V,rr: V>
+  Deepstd/core/hnd/Deep: forall<a,b> (result : a) -> resume-result<a,b>( result: bb: V )
+  Shallowstd/core/hnd/Shallow: forall<a,b> (result : a) -> resume-result<a,b>( result: bb: V )
+  Finalizestd/core/hnd/Finalize: forall<a,b> (result : b) -> resume-result<a,b>( result : rr: V )
+
+value type yldstd/core/hnd/yld: (E, V, V) -> V<ee: E,aa: V,rr: V>
+  Purestd/core/hnd/Pure: forall<e,a,b> yld<e,a,b>
+  YieldingFinalstd/core/hnd/YieldingFinal: forall<e,a,b> yld<e,a,b>
+  Yieldingstd/core/hnd/Yielding: forall<e,a,b> yld<e,a,b>
+  Yieldstd/core/hnd/Yield: forall<e,a,b,c> (clause : ((resume-result<c,b>) -> e b) -> e b, cont : (() -> c) -> e a) -> yld<e,a,b><bb: V>(clause : (resume-resultstd/core/hnd/resume-result: (V, V) -> V<bb: V,rr: V> -> ee: E rr: V) -> ee: E rr: V, cont : (() -> bstd/core/types/total: E) -> ee: E aa: V)
+
+extern guardstd/core/hnd/guard: forall<e> (w : evv<e>) -> e ()(ww: evv<$3403> : evvstd/core/hnd/evv: E -> V<ee: E> ) : ee: E (std/core/types/unit: V)std/core/types/unit: V
+  c  inline "kk_evv_guard(#1,kk_context())"
+  js "_guard"
+
+extern resume-finalstd/core/hnd/resume-final: forall<a> () -> a() : astd/core/types/total: E
+  c  inline "kk_fatal_resume_final(kk_context())"
+  js "_throw_resume_final"
+
+fun promptstd/core/hnd/prompt: forall<a,e,b,c> (w0 : evv<e>, w1 : evv<e>, ev : ev<b>, m : marker<e,c>, ret : (a) -> e c, result : a) -> e c( w0w0: evv<$4360> : evvstd/core/hnd/evv: E -> V<e0e0: E>,  w1w1: evv<$4360> : evvstd/core/hnd/evv: E -> V<e0e0: E>, evev: ev<$4361> : evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>, mm: marker<$4360,$4362> : markerstd/core/hnd/marker: (E, V) -> V<e0e0: E,rr: V>, retret: ($4359) -> $4360 $4362: aa: V -> e0e0: E rr: V, resultresult: $4359 : aa: V )result: -> 4690 4692 : e0e0: E rr: V
+  guardstd/core/hnd/guard: (w : evv<$4360>) -> $4360 ()(w1w1: evv<$4360>)
+  evv-setstd/core/hnd/evv-set: (w : evv<$4360>) -> $4360 ()(w0w0: evv<$4360>)  // restore the previous evidence vector
+  match yield-promptstd/core/hnd/yield-prompt: (m : marker<$4360,$4362>) -> $4360 yld<$4360,$4359,$4362>(mm: marker<$4360,$4362>)
+    Purestd/core/hnd/Pure: forall<e,a,b> yld<e,a,b> ->
+      // returning
+      retret: ($4359) -> $4360 $4362(resultresult: $4359)
+    YieldingFinalstd/core/hnd/YieldingFinal: forall<e,a,b> yld<e,a,b> ->
+      // yielding final (exception), keep yielding
+      keep-yielding-finalstd/core/hnd/keep-yielding-final: () -> $4360 $4362()
+    Yieldingstd/core/hnd/Yielding: forall<e,a,b> yld<e,a,b> ->
+      // regular yield, install a continuation
+      yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $4360 $4359, a) -> $4360 $4362) -> $4360 $4362 fnfn: forall<a> (cont : (a) -> $4360 $4359, res : a) -> $4360 $4362(contcont: ($4421) -> $4360 $4359,resres: $4421)
+        // we resume, continue under a fresh a prompt again
+        val w0'w0': evv<$4360> = evv-getstd/core/hnd/evv-get: () -> $4360 evv<$4360>()  // if not using scoped resumptions, w0' may be different from w0
+        val w1'w1': evv<$4360> = if (evv-eqstd/core/hnd/evv-eq: (evv0 : evv<$4360>, evv1 : evv<$4360>) -> $4360 bool(w0w0: evv<$4360>,w0'w0': evv<$4360>)) then w1w1: evv<$4360> else evv-insertstd/core/hnd/evv-insert: (evv : evv<$4360>, ev : ev<$4361>) -> $4360 evv<$4360>(w0'w0': evv<$4360>,evev: ev<$4361>)
+        evv-setstd/core/hnd/evv-set: (w : evv<$4360>) -> $4360 ()(w1'w1': evv<$4360>)
+        promptstd/core/hnd/prompt: (w0 : evv<$4360>, w1 : evv<$4360>, ev : ev<$4361>, m : marker<$4360,$4362>, ret : ($4359) -> $4360 $4362, result : $4359) -> $4360 $4362(w0'w0': evv<$4360>,w1'w1': evv<$4360>,evev: ev<$4361>,pretend-decreasingstd/core/undiv/pretend-decreasing: (x : marker<$4360,$4362>) -> $4360 marker<$4360,$4362>(mm: marker<$4360,$4362>),retret: ($4359) -> $4360 $4362,contcont: ($4421) -> $4360 $4359(resres: $4421));
+    Yieldstd/core/hnd/Yield: forall<e,a,b,c> (clause : ((resume-result<c,b>) -> e b) -> e b, cont : (() -> c) -> e a) -> yld<e,a,b>(clauseclause: ((resume-result<$4489,$4362>) -> $4360 $4362) -> $4360 $4362,contcont: (() -> $4489) -> $4360 $4359) ->
+      // yielded to the operation `clause` in our handler
+      fun resumeresume: (r : resume-result<$4489,$4362>) -> $4360 $4362(rr: resume-result<$4489,$4362>)result: -> $4360 $4362
+        match(rr: resume-result<$4489,$4362>)
+          Deepstd/core/hnd/Deep: forall<a,b> (result : a) -> resume-result<a,b>(xx: $4489) ->
+            val w0'w0': evv<$4360> = evv-getstd/core/hnd/evv-get: () -> $4360 evv<$4360>()  // if not using scoped resumptions, w0' may be different from w0
+            val w1'w1': evv<$4360> = if evv-eqstd/core/hnd/evv-eq: (evv0 : evv<$4360>, evv1 : evv<$4360>) -> $4360 bool(w0w0: evv<$4360>,w0'w0': evv<$4360>) then w1w1: evv<$4360> else evv-insertstd/core/hnd/evv-insert: (evv : evv<$4360>, ev : ev<$4361>) -> $4360 evv<$4360>(w0'w0': evv<$4360>,evev: ev<$4361>)
+            evv-setstd/core/hnd/evv-set: (w : evv<$4360>) -> $4360 ()(w1'w1': evv<$4360>)
+            promptstd/core/hnd/prompt: (w0 : evv<$4360>, w1 : evv<$4360>, ev : ev<$4361>, m : marker<$4360,$4362>, ret : ($4359) -> $4360 $4362, result : $4359) -> $4360 $4362(w0'w0': evv<$4360>,w1'w1': evv<$4360>,evev: ev<$4361>,pretend-decreasingstd/core/undiv/pretend-decreasing: (x : marker<$4360,$4362>) -> $4360 marker<$4360,$4362>(mm: marker<$4360,$4362>),retret: ($4359) -> $4360 $4362,contcont: (() -> $4489) -> $4360 $4359({xx: $4489}))
+          Shallowstd/core/hnd/Shallow: forall<a,b> (result : a) -> resume-result<a,b>(xx: $4489) ->
+            yield-bindstd/core/hnd/yield-bind: (x : $4359, next : ($4359) -> $4360 $4362) -> $4360 $4362( contcont: (() -> $4489) -> $4360 $4359({xx: $4489}), fnfn: (y : $4359) -> $4360 $4362(yy: $4359) retret: ($4359) -> $4360 $4362(yy: $4359) )
+          Finalizestd/core/hnd/Finalize: forall<a,b> (result : b) -> resume-result<a,b>(xx: $4362) ->
+            val w0'w0': evv<$4360> = evv-getstd/core/hnd/evv-get: () -> $4360 evv<$4360>()  // if not using scoped resumptions, w0' may be different from w0
+            val w1'w1': evv<$4360> = if evv-eqstd/core/hnd/evv-eq: (evv0 : evv<$4360>, evv1 : evv<$4360>) -> $4360 bool(w0w0: evv<$4360>,w0'w0': evv<$4360>) then w1w1: evv<$4360> else evv-insertstd/core/hnd/evv-insert: (evv : evv<$4360>, ev : ev<$4361>) -> $4360 evv<$4360>(w0'w0': evv<$4360>,evev: ev<$4361>)
+            evv-setstd/core/hnd/evv-set: (w : evv<$4360>) -> $4360 ()(w1'w1': evv<$4360>)
+            promptstd/core/hnd/prompt: (w0 : evv<$4360>, w1 : evv<$4360>, ev : ev<$4361>, m : marker<$4360,$4362>, ret : ($4359) -> $4360 $4362, result : $4359) -> $4360 $4362(w0'w0': evv<$4360>,w1'w1': evv<$4360>,evev: ev<$4361>,pretend-decreasingstd/core/undiv/pretend-decreasing: (x : marker<$4360,$4362>) -> $4360 marker<$4360,$4362>(mm: marker<$4360,$4362>),retret: ($4359) -> $4360 $4362,contcont: (() -> $4489) -> $4360 $4359({ yield-to-finalstd/core/hnd/yield-to-final: (m : marker<$4360,$4362>, clause : ((resume-result<$4489,$4362>) -> $4360 $4362) -> $4360 $4362) -> $4489(mm: marker<$4360,$4362>, fnfn: ((resume-result<$4489,$4362>) -> $4360 $4362) -> $4360 $4362(_k) xx: $4362) }))
+      clauseclause: ((resume-result<$4489,$4362>) -> $4360 $4362) -> $4360 $4362(resumeresume: (r : resume-result<$4489,$4362>) -> $4360 $4362) // TODO: we should exit prompt first, and then execute clause to use constant stack space when resuming
+
+pub noinline fun @hhandle( tagtag: htag<$4708>:htagstd/core/hnd/htag: ((E, V) -> V) -> V<hh: (E, V) -> V>, hh: $4708<$4706,$4709> : hh: (E, V) -> V<ee: E,rr: V>, retret: ($4705) -> $4706 $4709: aa: V -> ee: E rr: V, actionaction: () -> $4707 $4705 : () -> e1e1: E aa: V )result: -> 4802 4805 : ee: E rr: V
+  // insert new evidence for our handler
+  val w0w0: evv<$4706> = evv-getstd/core/hnd/evv-get: () -> $4706 evv<$4706>()
+  val mm: marker<$4706,$4709>  = fresh-markerstd/core/hnd/fresh-marker: () -> $4706 marker<$4706,$4709>()
+  val evev: ev<$4708> = Evstd/core/hnd/Ev: forall<a,e,b> (htag : htag<a>, marker : marker<e,b>, hnd : a<e,b>, hevv : evv<e>) -> ev<a>(tagtag: htag<$4708>,mm: marker<$4706,$4709>,hh: $4708<$4706,$4709>,w0w0: evv<$4706>)
+  val w1w1: evv<$4706> = evv-insertstd/core/hnd/evv-insert: (evv : evv<$4706>, ev : ev<$4708>) -> $4706 evv<$4706>(w0w0: evv<$4706>,evev: ev<$4708>)
+  evv-setstd/core/hnd/evv-set: (w : evv<$4706>) -> $4706 ()(w1w1: evv<$4706>)
+  // call action first (this may be yielding), then check the result
+  promptstd/core/hnd/prompt: (w0 : evv<$4706>, w1 : evv<$4706>, ev : ev<$4708>, m : marker<$4706,$4709>, ret : ($4705) -> $4706 $4709, result : $4705) -> $4706 $4709(w0w0: evv<$4706>,w1w1: evv<$4706>,evev: ev<$4708>,mm: marker<$4706,$4709>,retret: ($4705) -> $4706 $4709,cast-ev0std/core/hnd/cast-ev0: (f : () -> $4707 $4705) -> $4706 (() -> $4706 $4705)(actionaction: () -> $4707 $4705)())
+
+// -------------------------------------------
+// named handler
+// (which is not inserted into the evidence vector)
+// -------------------------------------------
+
+pub noinline fun @named-handle( tagtag: htag<$5033>:htagstd/core/hnd/htag: ((E, V) -> V) -> V<hh: (E, V) -> V>, hh: $5033<$5031,$5034> : hh: (E, V) -> V<ee: E,rr: V>, retret: ($5030) -> $5031 $5034: aa: V -> ee: E rr: V, actionaction: (ev<$5033>) -> $5032 $5030 : evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V> -> e1e1: E aa: V )result: -> 5111 5114 : ee: E rr: V
+  val mm: marker<$5031,$5034> = fresh-marker-namedstd/core/hnd/fresh-marker-named: () -> $5031 marker<$5031,$5034>()            // unique (negative) marker, but never gets inserted into the evidence vector
+  val w0w0: evv<$5031> = evv-getstd/core/hnd/evv-get: () -> $5031 evv<$5031>()
+  val evev: ev<$5033> = Evstd/core/hnd/Ev: forall<a,e,b> (htag : htag<a>, marker : marker<e,b>, hnd : a<e,b>, hevv : evv<e>) -> ev<a>(tagtag: htag<$5033>,mm: marker<$5031,$5034>,hh: $5033<$5031,$5034>,w0w0: evv<$5031>)
+  promptstd/core/hnd/prompt: (w0 : evv<$5031>, w1 : evv<$5031>, ev : ev<$5033>, m : marker<$5031,$5034>, ret : ($5030) -> $5031 $5034, result : $5030) -> $5031 $5034(w0w0: evv<$5031>,w0w0: evv<$5031>,evev: ev<$5033>,mm: marker<$5031,$5034>,retret: ($5030) -> $5031 $5034,cast-ev1std/core/hnd/cast-ev1: (f : (ev<$5033>) -> $5032 $5030) -> $5031 ((ev<$5033>) -> $5031 $5030)(actionaction: (ev<$5033>) -> $5032 $5030)(evev: ev<$5033>))
+
+
+// -------------------------------------------
+// mask
+// -------------------------------------------
+
+fun mask-at1std/core/hnd/mask-at1: forall<a,b,e,e1> (i : ev-index, behind : bool, action : (a) -> e b, x : a) -> e1 b( ii: ev-index : ev-indexstd/core/hnd/ev-index: V, behindbehind: bool : boolstd/core/types/bool: V, actionaction: ($4821) -> $4823 $4822 : (aa: V) -> e1e1: E bb: V, xx: $4821 : aa: V )result: -> 4921 4919 : e2e2: E bb: V
+  val w0w0: evv<_4830> = evv-swap-deletestd/core/hnd/evv-swap-delete: (i : ev-index, behind : bool) -> $4824 evv<_4830>(ii: ev-index,behindbehind: bool)
+  val yy: $4822 = cast-ev1std/core/hnd/cast-ev1: (f : ($4821) -> $4823 $4822) -> $4824 (($4821) -> $4824 $4822)(actionaction: ($4821) -> $4823 $4822)(xx: $4821)
+  evv-setstd/core/hnd/evv-set: (w : evv<_4830>) -> $4824 ()(w0w0: evv<_4830>)
+  if yieldingstd/core/hnd/yielding: () -> $4824 bool() returnreturn: $4822 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $4824 $4822, a) -> $4824 $4822) -> $4824 $4822( fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($4874) -> $4824 $4822,resres: $4874) mask-at1std/core/hnd/mask-at1: (i : ev-index, behind : bool, action : ($4874) -> $4824 $4822, x : $4874) -> $4824 $4822(pretend-decreasingstd/core/undiv/pretend-decreasing: (x : ev-index) -> $4824 ev-index(ii: ev-index),behindbehind: bool,contcont: ($4874) -> $4824 $4822,resres: $4874) )std/core/types/Unit: ()
+  yy: $4822
+
+pub fun @mask-at<aa: V,e1e1: E,e2e2: E>( ii: ev-index : ev-indexstd/core/hnd/ev-index: V, behindbehind: bool : boolstd/core/types/bool: V, actionaction: () -> $4935 $4934 : () -> e1e1: E aa: V )result: -> 5020 5018 : e2e2: E aa: V
+  val w0w0: evv<_4942> = evv-swap-deletestd/core/hnd/evv-swap-delete: (i : ev-index, behind : bool) -> $4936 evv<_4942>(ii: ev-index,behindbehind: bool)
+  val xx: $4934 = cast-ev0std/core/hnd/cast-ev0: (f : () -> $4935 $4934) -> $4936 (() -> $4936 $4934)(actionaction: () -> $4935 $4934)()
+  evv-setstd/core/hnd/evv-set: (w : evv<_4942>) -> $4936 ()(w0w0: evv<_4942>)
+  if yieldingstd/core/hnd/yielding: () -> $4936 bool() returnreturn: $4934 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $4936 $4934, a) -> $4936 $4934) -> $4936 $4934( fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($4982) -> $4936 $4934,resres: $4982) mask-at1std/core/hnd/mask-at1: (i : ev-index, behind : bool, action : ($4982) -> $4936 $4934, x : $4982) -> $4936 $4934(ii: ev-index,behindbehind: bool,contcont: ($4982) -> $4936 $4934,resres: $4982) )std/core/types/Unit: ()
+  xx: $4934
+
+// mask for builtin effects without a handler or evidence (like `:st` or `:local`)
+pub fun @mask-builtin<aa: V,e1e1: E,e2e2: E>( actionaction: () -> $2657 $2656 : () -> e1e1: E aa: V )result: -> 2681 2679 : e2e2: E aa: V
+  cast-ev0std/core/hnd/cast-ev0: (f : () -> $2657 $2656) -> $2658 (() -> $2658 $2656)(actionaction: () -> $2657 $2656)()
+
+
+// -------------------------------------------
+// Local variables
+// -------------------------------------------
+
+fun prompt-local-varstd/core/hnd/prompt-local-var: forall<a,b,h> (loc : local-var<h,a>, res : b) -> <div,local<h>> b(locloc: local-var<$9664,$9661>:local-varstd/core/types/local-var: (H, V) -> V<ss: H,aa: V>, resres: $9662 : bb: V  )result: -> <div,local<9758>|9757> 9756 : <divstd/core/types/div: X,localstd/core/types/local: H -> X<ss: H>|std/core/types/effect-extend: (X, E) -> Eee: E> bb: V
+  if !std/core/types/bool/(!): (b : bool) -> <div,local<$9664>|$9663> boolyieldingstd/core/hnd/yielding: () -> <div,local<$9664>|$9663> bool() returnreturn: $9662 resres: $9662;
+  val vv: $9661 = locloc: $9661
+  yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> <div,local<$9664>|$9663> $9662, a) -> <div,local<$9664>|$9663> $9662) -> <div,local<$9664>|$9663> $9662(fnfn: forall<a,e> (cont : (a) -> <div,local<$9664>|e> $9662, x : a) -> <div,local<$9664>|e> $9662(contcont: ($9710) -> <div,local<$9664>|$9663> $9662,xx: $9710){ locloc: local-var<$9664,$9661> :=std/core/types/local-set: (v : local-var<$9664,$9661>, assigned : $9661) -> <local<$9664>,div|$9663> () vv: $9661; prompt-local-varstd/core/hnd/prompt-local-var: (loc : local-var<$9664,$9661>, res : $9662) -> <div,local<$9664>|$9663> $9662(@byref(locloc: local-var<$9664,$9661>),contcont: ($9710) -> <div,local<$9664>|$9663> $9662(xx: $9710)) } )  // restore state early before the resume
+
+pub inline fun local-varstd/core/hnd/local-var: forall<a,b,e,h> (init : a, action : (l : local-var<h,a>) -> <local<h>|e> b) -> <local<h>|e> b(initinit: $9789:aa: V, actionaction: (l : local-var<$9792,$9789>) -> <local<$9792>|$9791> $9790: (l:local-varstd/core/types/local-var: (H, V) -> V<ss: H,aa: V>) -> <localstd/core/types/local: H -> X<ss: H>|std/core/types/effect-extend: (X, E) -> Eee: E> bb: V )result: -> <local<9857>|9856> 9855 : <localstd/core/types/local: H -> X<ss: H>|std/core/types/effect-extend: (X, E) -> Eee: E> bb: V
+  pretend-no-divstd/core/undiv/pretend-no-div: (action : () -> <div,local<$9792>|$9791> $9790) -> <local<$9792>|$9791> $9790
+    val locloc: local-var<$9792,$9789> : local-varstd/core/types/local-var: (H, V) -> V<__w-l464-c25: H,__w-l464-c27: V> = local-newstd/core/types/local-new: (value : $9789) -> <local<$9792>,div|$9791> local-var<$9792,$9789>(initinit: $9789)
+    val resres: $9790 = cast-ev1std/core/hnd/cast-ev1: (f : (local-var<$9792,$9789>) -> <local<$9792>|$9791> $9790) -> <div,local<$9792>|$9791> ((local-var<$9792,$9789>) -> <div,local<$9792>|$9791> $9790)(actionaction: (l : local-var<$9792,$9789>) -> <local<$9792>|$9791> $9790)(@byref(locloc: local-var<$9792,$9789>))
+    prompt-local-varstd/core/hnd/prompt-local-var: (loc : local-var<$9792,$9789>, res : $9790) -> <div,local<$9792>|$9791> $9790(@byref(locloc: local-var<$9792,$9789>),resres: $9790)
+
+
+// -------------------------------------------
+// Finally
+// -------------------------------------------
+
+pub fun finallystd/core/hnd/finally: forall<a,e> (fin : () -> e (), action : () -> e a) -> e a( finfin: () -> $9406 () : () -> ee: E (std/core/types/unit: V)std/core/types/unit: V, actionaction: () -> $9406 $9405 : () -> ee: E aa: V )result: -> 9422 9421 : ee: E aa: V
+  finally-promptstd/core/hnd/finally-prompt: (fin : () -> $9406 (), res : $9405) -> $9406 $9405(finfin: () -> $9406 (), actionaction: () -> $9406 $9405());
+
+fun finally-promptstd/core/hnd/finally-prompt: forall<a,e> (fin : () -> e (), res : a) -> e a(finfin: () -> $9294 () : () -> ee: E (std/core/types/unit: V)std/core/types/unit: V, resres: $9293 : aa: V )result: -> 9398 9397 : ee: E aa: V
+  if !std/core/types/bool/(!): (b : bool) -> $9294 boolyieldingstd/core/hnd/yielding: () -> $9294 bool() then
+    finfin: () -> $9294 ()()
+    resres: $9293
+  elif yielding-non-finalstd/core/hnd/yielding-non-final: () -> $9294 bool() then
+    yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $9294 $9293, a) -> $9294 $9293) -> $9294 $9293(fnfn: forall<a> (cont : (a) -> $9294 $9293, x : a) -> $9294 $9293(contcont: ($9328) -> $9294 $9293,xx: $9328){ finally-promptstd/core/hnd/finally-prompt: (fin : () -> $9294 (), res : $9293) -> $9294 $9293(pretend-decreasingstd/core/undiv/pretend-decreasing: (x : () -> $9294 ()) -> $9294 (() -> $9294 ())(finfin: () -> $9294 ()),contcont: ($9328) -> $9294 $9293(xx: $9328)) })
+  else
+    val yldyld: yield-info = yield-capturestd/core/hnd/yield-capture: () -> $9294 yield-info()
+    finfin: () -> $9294 ()()
+    if yieldingstd/core/hnd/yielding: () -> $9294 bool() returnreturn: $9293 yield-extendstd/core/hnd/yield-extend: (next : (_9366) -> $9294 $9293) -> $9294 $9293( fnfn: (_9366) -> $9294 $9293(_x) unsafe-reyieldstd/core/hnd/unsafe-reyield: (yld : yield-info) -> $9294 $9293(yldyld: yield-info) )std/core/types/Unit: ()
+    unsafe-reyieldstd/core/hnd/unsafe-reyield: (yld : yield-info) -> $9294 $9293(yldyld: yield-info)
+
+/*
+fun finalize(cont : (() -> b) -> e r, res : a) : e a
+  val m : marker<_e,_r> = fresh-marker()
+  val w = evv-get()
+  prompt(w,w,ev-none(),m,id, yield-bind( cont({ yield-to-final(m,fn(_k) res) }), fn(_x) res ))  // TODO: special prompt that does not insert on resume?
+*/
+
+// -------------------------------------------
+// Initially
+// -------------------------------------------
+
+// add integers
+inline extern addstd/core/hnd/add: (i : int, j : int) -> int(i : intstd/core/types/int: V, j : intstd/core/types/int: V) : intstd/core/types/int: V
+  c  "kk_integer_add"
+  cs inline "(#1 + #2)"
+  js inline "(#1 + #2)" // "$std_core_types._int_add"
+
+// are two integers equal?
+inline extern eqstd/core/hnd/eq: (x : int, y : int) -> bool( ^x : intstd/core/types/int: V, ^y : intstd/core/types/int: V) : boolstd/core/types/bool: V
+  c  "kk_integer_eq_borrow"
+  cs inline "(#1 == #2)"
+  js inline "(#1 == #2)" // $std_core_types._int_eq"
+
+
+pub fun initiallystd/core/hnd/initially: forall<a,e> (init : (int) -> e (), action : () -> e a) -> e a(initinit: (int) -> $9608 () : (intstd/core/types/int: V) -> ee: E (std/core/types/unit: V)std/core/types/unit: V, actionaction: () -> $9608 $9607 : () -> ee: E aa: V )result: -> 9654 9653 : ee: E aa: V
+  initinit: (int) -> $9608 ()(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) + if yieldingstd/core/hnd/yielding: () -> $9608 bool() returnreturn: $9607 yield-extendstd/core/hnd/yield-extend: (next : (()) -> $9608 $9607) -> $9608 $9607(fnfn: (()) -> $9608 $9607(_ret:(std/core/types/unit: V)std/core/types/unit: V) initially-promptstd/core/hnd/initially-prompt: (init : (int) -> $9608 (), res : $9607) -> $9608 $9607(initinit: (int) -> $9608 (),actionaction: () -> $9608 $9607()) )std/core/types/Unit: () + initially-promptstd/core/hnd/initially-prompt: (init : (int) -> $9608 (), res : $9607) -> $9608 $9607(initinit: (int) -> $9608 (), actionaction: () -> $9608 $9607()
) + +fun initially-promptstd/core/hnd/initially-prompt: forall<a,e> (init : (int) -> e (), res : a) -> e a( initinit: (int) -> $9430 () : (intstd/core/types/int: V) -> ee: E (std/core/types/unit: V)std/core/types/unit: V, resres: $9429 : aa: V )result: -> 9600 9599 : ee: E aa: V + if yielding-non-finalstd/core/hnd/yielding-non-final: () -> $9430 bool() then + val countcount: ref<global,int> = unsafe-ststd/core/hnd/unsafe-st: (f : () -> <st<global>|$9430> ref<global,int>) -> $9430 (() -> $9430 ref<global,int>){refstd/core/types/ref: (value : int) -> <alloc<global>,read<global>,write<global>|$9430> ref<global,int>(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
)}() + yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $9430 $9429, a) -> $9430 $9429) -> $9430 $9429(fnfn: forall<a> (cont : (a) -> $9430 $9429, x : a) -> $9430 $9429(contcont: ($9467) -> $9430 $9429,xx: $9467) + val cntcnt: int = unsafe-ststd/core/hnd/unsafe-st: (f : () -> <st<global>|$9430> int) -> $9430 (() -> $9430 int){ !std/core/types/ref/(!): (ref : ref<global,int>) -> <read<global>,alloc<global>,write<global>|$9430> intcountcount: ref<global,int> }() // increase counter on every resumption + unsafe-ststd/core/hnd/unsafe-st: (f : () -> <st<global>|$9430> ()) -> $9430 (() -> $9430 ()){ countcount: ref<global,int> :=std/core/types/set: (ref : ref<global,int>, assigned : int) -> <write<global>,alloc<global>,read<global>|$9430> () addstd/core/hnd/add: (i : int, j : int) -> <write<global>,alloc<global>,read<global>|$9430> int(cntcnt: int,1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
) }() + if eqstd/core/hnd/eq: (x : int, y : int) -> $9430 bool(cntcnt: int,0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) then (std/core/types/Unit: ())std/core/types/Unit: () else // for every resume after the first, run the initializer + val rr: () = initinit: (int) -> $9430 ()(cntcnt: int) + if yieldingstd/core/hnd/yielding: () -> $9430 bool() + then { yield-extendstd/core/hnd/yield-extend: (next : (_9546) -> $9430 $9429) -> $9430 $9429( fnfn: (_9546) -> $9430 $9429(_ret) initially-promptstd/core/hnd/initially-prompt: (init : (int) -> $9430 (), res : $9429) -> $9430 $9429(pretend-decreasingstd/core/undiv/pretend-decreasing: (x : (int) -> $9430 ()) -> $9430 ((int) -> $9430 ())(initinit: (int) -> $9430 ()), contcont: ($9467) -> $9430 $9429(xx: $9467)) ); (std/core/types/Unit: ())std/core/types/Unit: () }std/core/types/Unit: () + initially-promptstd/core/hnd/initially-prompt: (init : (int) -> $9430 (), res : $9429) -> $9430 $9429(pretend-decreasingstd/core/undiv/pretend-decreasing: (x : (int) -> $9430 ()) -> $9430 ((int) -> $9430 ())(initinit: (int) -> $9430 ()), contcont: ($9467) -> $9430 $9429(xx: $9467)) + ) + else resres: $9429
+ + +// ------------------------------------------- +// Resume context +// ------------------------------------------- + +abstract value struct resume-contextstd/core/hnd/resume-context: (V, E, E, V) -> V<bb: V,ee: E::E,e0e0: E::E,rr: V>( kresult: -> total (resume-result<2445,2448>) -> 2446 2448 : resume-resultstd/core/hnd/resume-result: (V, V) -> V<bb: V,rr: V> -> ee: E rr: V ) + +pub fun resumestd/core/hnd/resume: forall<a,e,e1,b> (r : resume-context<a,e,e1,b>, x : a) -> e b( rr: resume-context<$4161,$4162,$4163,$4164> : resume-contextstd/core/hnd/resume-context: (V, E, E, V) -> V<bb: V,ee: E,e0e0: E,rr: V>, xx: $4161 : bb: V )result: -> 4201 4203 : ee: E rr: V + (rr: resume-context<$4161,$4162,$4163,$4164>.kstd/core/hnd/resume-context/k: (resume-context<$4161,$4162,$4163,$4164>) -> $4162 ((resume-result<$4161,$4164>) -> $4162 $4164))(Deepstd/core/hnd/Deep: forall<a,b> (result : a) -> resume-result<a,b>(xx: $4161)) + +pub fun resume-shallowstd/core/hnd/resume-shallow: forall<a,e,e1,b> (r : resume-context<a,e,e1,b>, x : a) -> e1 b( rr: resume-context<$4232,$4233,$4234,$4235> : resume-contextstd/core/hnd/resume-context: (V, E, E, V) -> V<bb: V,ee: E,e0e0: E,rr: V>, xx: $4232 : bb: V )result: -> 4288 4289 : e0e0: E rr: V + cast-ev1std/core/hnd/cast-ev1: (f : (resume-result<$4232,$4235>) -> $4233 $4235) -> $4234 ((resume-result<$4232,$4235>) -> $4234 $4235)(rr: resume-context<$4232,$4233,$4234,$4235>.kstd/core/hnd/resume-context/k: (resume-context<$4232,$4233,$4234,$4235>) -> $4234 ((resume-result<$4232,$4235>) -> $4233 $4235))(Shallowstd/core/hnd/Shallow: forall<a,b> (result : a) -> resume-result<a,b>(xx: $4232)) + + +pub fun finalizestd/core/hnd/finalize: forall<a,e,e1,b> (r : resume-context<a,e,e1,b>, x : b) -> e b( rr: resume-context<$7102,$7103,$7104,$7105> : resume-contextstd/core/hnd/resume-context: (V, E, E, V) -> V<bb: V,ee: E,e0e0: E,rr: V>, xx: $7105 : rr: V )result: -> 7142 7144 : ee: E rr: V + //finalize(r.k,x) + (rr: resume-context<$7102,$7103,$7104,$7105>.kstd/core/hnd/resume-context/k: (resume-context<$7102,$7103,$7104,$7105>) -> $7103 ((resume-result<$7102,$7105>) -> $7103 $7105))(Finalizestd/core/hnd/Finalize: forall<a,b> (result : b) -> resume-result<a,b>(xx: $7105)) + +// ------------------------------------------- +// Clauses +// ------------------------------------------- + +abstract value type clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<aa: V::V,bb: V::V,hh: (E, V) -> V::(E,V)->V,ee: E::E,rr: V::V> + Clause1std/core/hnd/Clause1: forall<a,b,c,e,d> (clause : (marker<e,d>, ev<c>, a) -> e b) -> clause1<a,b,c,e,d>( clausestd/core/hnd/clause1/clause: forall<a,b,c,e,d> (clause1 : clause1<a,b,c,e,d>) -> ((marker<e,d>, ev<c>, a) -> e b): (markerstd/core/hnd/marker: (E, V) -> V<ee: E,rr: V>, evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>, aa: V) -> ee: E bb: V ) + +inline extern cast-clause0std/core/hnd/cast-clause0: forall<a,e,e1,b,c> (f : (marker<e1,c>, ev<b>) -> e1 a) -> e ((marker<e1,c>, ev<b>) -> e a)( f : (markerstd/core/hnd/marker: (E, V) -> V<e1e1: E,rr: V>,evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>) -> e1e1: E bb: V) : ee: E ((markerstd/core/hnd/marker: (E, V) -> V<e1e1: E,rr: V>,evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>) -> ee: E bb: V) + inline "#1" + +inline extern cast-clause1std/core/hnd/cast-clause1: forall<a,b,e,e1,c,d> (f : (marker<e1,d>, ev<c>, a) -> e1 b) -> e ((marker<e1,d>, ev<c>, a) -> e b)( f : (markerstd/core/hnd/marker: (E, V) -> V<e1e1: E,rr: V>,evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>,aa: V) -> e1e1: E bb: V) : ee: E ((markerstd/core/hnd/marker: (E, V) -> V<e1e1: E,rr: V>,evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>,aa: V) -> ee: E bb: V) + inline "#1" + +inline extern cast-clause2std/core/hnd/cast-clause2: forall<a,b,c,e,e1,d,a1> (f : (marker<e1,a1>, ev<d>, a, b) -> e1 c) -> e ((marker<e1,a1>, ev<d>, a, b) -> e c)( f : (markerstd/core/hnd/marker: (E, V) -> V<e1e1: E,rr: V>,evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>,a1a1: V,a2a2: V) -> e1e1: E bb: V) : ee: E ((markerstd/core/hnd/marker: (E, V) -> V<e1e1: E,rr: V>,evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>,a1a1: V,a2a2: V) -> ee: E bb: V) + inline "#1" + + +pub inline fun @perform1<aa: V,bb: V,hh: (E, V) -> V>( evev: ev<$3133> : evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>, opop: forall<e,a> ($3133<e,a>) -> clause1<$3131,$3132,$3133,e,a> : (forall<e1e1: E,rr: V> hh: (E, V) -> V<e1e1: E,rr: V> -> clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<aa: V,bb: V,hh: (E, V) -> V,e1e1: E,rr: V>), xx: $3131 : aa: V )result: -> 3201 3199 : ee: E bb: V + match evev: ev<$3133> + Evstd/core/hnd/Ev: forall<a,e,b> (htag : htag<a>, marker : marker<e,b>, hnd : a<e,b>, hevv : evv<e>) -> ev<a>(_tag,mm: marker<$3137,$3138>,hh: $3133<$3137,$3138>,_w) -> match hh: $3133<$3137,$3138>.opop: ($3133<$3137,$3138>) -> $3134 clause1<$3131,$3132,$3133,$3137,$3138> + Clause1std/core/hnd/Clause1: forall<a,b,c,e,d> (clause : (marker<e,d>, ev<c>, a) -> e b) -> clause1<a,b,c,e,d>(ff: (marker<$3137,$3138>, ev<$3133>, $3131) -> $3137 $3132) -> cast-clause1std/core/hnd/cast-clause1: (f : (marker<$3137,$3138>, ev<$3133>, $3131) -> $3137 $3132) -> $3134 ((marker<$3137,$3138>, ev<$3133>, $3131) -> $3134 $3132)(ff: (marker<$3137,$3138>, ev<$3133>, $3131) -> $3137 $3132)(mm: marker<$3137,$3138>,evev: ev<$3133>,xx: $3131) + +fun evv-swap-withstd/core/hnd/evv-swap-with: forall<a,e> (ev : ev<a>) -> evv<e>(evev: ev<$3944> : evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>)result: -> total evv<8937> + match(evev: ev<$3944>) + Evstd/core/hnd/Ev: forall<a,e,b> (htag : htag<a>, marker : marker<e,b>, hnd : a<e,b>, hevv : evv<e>) -> ev<a>(_tag,_m,_h,ww: evv<$3947>) -> evv-swapstd/core/hnd/evv-swap: (w : evv<$3947>) -> evv<_3964>(ww: evv<$3947>) + +inline fun under1std/core/hnd/under1: forall<a,b,e,c> (ev : ev<c>, op : (a) -> e b, x : a) -> e b( evev: ev<$8622> : evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>, opop: ($8619) -> $8621 $8620 : aa: V -> ee: E bb: V, xx: $8619 : aa: V )result: -> 8703 8702 : ee: E bb: V + val w0w0: evv<_8630> = evv-swap-withstd/core/hnd/evv-swap-with: (ev : ev<$8622>) -> $8621 evv<_8630>(evev: ev<$8622>) + val yy: $8620 = opop: ($8619) -> $8621 $8620(xx: $8619) + // evv-set(w0) // only needed before yielding for evidence expected check in prompt + if yieldingstd/core/hnd/yielding: () -> $8621 bool() returnreturn: $8620 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $8621 $8620, a) -> $8621 $8620) -> $8621 $8620( fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($8650) -> $8621 $8620,resres: $8650) under1xstd/core/hnd/under1x: (ev : ev<$8622>, op : ($8650) -> $8621 $8620, x : $8650) -> $8621 $8620(pretend-decreasingstd/core/undiv/pretend-decreasing: (x : ev<$8622>) -> $8621 ev<$8622>(evev: ev<$8622>),contcont: ($8650) -> $8621 $8620,resres: $8650) )std/core/types/Unit: () + evv-setstd/core/hnd/evv-set: (w : evv<_8630>) -> $8621 ()(w0w0: evv<_8630>) + yy: $8620 + +// extra under1x to make under1 inlineable +noinline fun under1xstd/core/hnd/under1x: forall<a,b,e,c> (ev : ev<c>, op : (a) -> e b, x : a) -> e b( evev: ev<$8524> : evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>, opop: ($8521) -> $8523 $8522 : aa: V -> ee: E bb: V, xx: $8521 : aa: V )result: -> 8605 8604 : ee: E bb: V + val w0w0: evv<_8532> = evv-swap-withstd/core/hnd/evv-swap-with: (ev : ev<$8524>) -> $8523 evv<_8532>(evev: ev<$8524>) + val yy: $8522 = opop: ($8521) -> $8523 $8522(xx: $8521) + // evv-set(w0) // only needed before yielding for evidence expected check in prompt + if yieldingstd/core/hnd/yielding: () -> $8523 bool() returnreturn: $8522 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $8523 $8522, a) -> $8523 $8522) -> $8523 $8522( fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($8552) -> $8523 $8522,resres: $8552) under1xstd/core/hnd/under1x: (ev : ev<$8524>, op : ($8552) -> $8523 $8522, x : $8552) -> $8523 $8522(pretend-decreasingstd/core/undiv/pretend-decreasing: (x : ev<$8524>) -> $8523 ev<$8524>(evev: ev<$8524>),contcont: ($8552) -> $8523 $8522,resres: $8552) )std/core/types/Unit: () + evv-setstd/core/hnd/evv-set: (w : evv<_8532>) -> $8523 ()(w0w0: evv<_8532>) + yy: $8522 + +pub fun clause-control-raw1std/core/hnd/clause-control-raw1: forall<a,b,e,e1,c,d> (op : (x : a, r : resume-context<b,e,e1,d>) -> e d) -> clause1<a,b,c,e,d>( opop: (x : $6810, r : resume-context<$6811,$6812,$6813,$6815>) -> $6812 $6815 : (x:aa: V, r: resume-contextstd/core/hnd/resume-context: (V, E, E, V) -> V<bb: V,ee: E,e0e0: E,rr: V>) -> ee: E rr: V )result: -> total clause1<6879,6880,6883,6881,6884> : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<aa: V,bb: V,hh: (E, V) -> V,ee: E,rr: V> + Clause1std/core/hnd/Clause1: forall<a,b,c,e,d> (clause : (marker<e,d>, ev<c>, a) -> e b) -> clause1<a,b,c,e,d>(fnfn: (m : marker<$6812,$6815>, ev<$6814>, x : $6810) -> $6812 $6811(mm: marker<$6812,$6815>,_ev,xx: $6810){ yield-tostd/core/hnd/yield-to: (m : marker<$6812,$6815>, clause : ((resume-result<$6811,$6815>) -> $6812 $6815) -> $6812 $6815) -> $6812 $6811(mm: marker<$6812,$6815>, fnfn: (k : (resume-result<$6811,$6815>) -> $6812 $6815) -> $6812 $6815(kk: (resume-result<$6811,$6815>) -> $6812 $6815){ opop: (x : $6810, r : resume-context<$6811,$6812,$6813,$6815>) -> $6812 $6815(xx: $6810,Resume-contextstd/core/hnd/Resume-context: forall<a,e,e1,b> (k : (resume-result<a,b>) -> e b) -> resume-context<a,e,e1,b>(kk: (resume-result<$6811,$6815>) -> $6812 $6815)) } ) } ) + +fun getstd/core/hnd/get: forall<a,h> (ref : ref<h,a>) -> <read<h>,div> a( refref: ref<$4130,$4129>: refstd/core/types/ref: (H, V) -> V<hh: H,aa: V>)result: -> <read<4153>,div> 4152 : <std/core/types/total: Ereadstd/core/types/read: H -> X<hh: H>,divstd/core/types/div: X> aa: V + !std/core/types/ref/(!): (ref : ref<$4130,$4129>) -> <read<$4130>,div> $4129refref: ref<$4130,$4129> + +inline extern unsafe-ststd/core/hnd/unsafe-st: forall<a,e> (f : () -> <st<global>|e> a) -> (() -> e a)(f : () -> <ststd/core/types/st: H -> E<globalstd/core/types/global: H>|ee: E> aa: V ) : ((std/core/types/total: E) -> ee: E aa: V) + inline "#1" + +fun protect-checkstd/core/hnd/protect-check: forall<a,e,b> (resumed : ref<global,bool>, k : (resume-result<a,b>) -> e b, res : b) -> e b( resumedresumed: ref<global,bool> : refstd/core/types/ref: (H, V) -> V<globalstd/core/types/global: H,boolstd/core/types/bool: V>, kk: (resume-result<$7157,$7159>) -> $7158 $7159 : resume-resultstd/core/hnd/resume-result: (V, V) -> V<bb: V,rr: V> -> ee: E rr: V, resres: $7159 : rr: V )result: -> 7224 7225 : ee: E rr: V + val did-resumedid-resume: bool : boolstd/core/types/bool: V = (unsafe-ststd/core/hnd/unsafe-st: (f : () -> <st<global>|$7158> bool) -> $7158 (() -> $7158 bool){ !std/core/types/ref/(!): (ref : ref<global,bool>) -> <read<global>,alloc<global>,write<global>|$7158> boolresumedresumed: ref<global,bool> })() + if !std/core/types/bool/(!): (b : bool) -> $7158 booldid-resumedid-resume: bool + then kk: (resume-result<$7157,$7159>) -> $7158 $7159(Finalizestd/core/hnd/Finalize: forall<a,b> (result : b) -> resume-result<a,b>(resres: $7159)) //finalize(k,res) + else resres: $7159 + +fun protectstd/core/hnd/protect: forall<a,b,e,c> (x : a, clause : (x : a, k : (b) -> e c) -> e c, k : (resume-result<b,c>) -> e c) -> e c( xx: $7235 : aa: V, clauseclause: (x : $7235, k : ($7236) -> $7237 $7238) -> $7237 $7238 : (x:aa: V, k: bb: V -> ee: E rr: V) -> ee: E rr: V, kk: (resume-result<$7236,$7238>) -> $7237 $7238 : resume-resultstd/core/hnd/resume-result: (V, V) -> V<bb: V,rr: V> -> ee: E rr: V )result: -> 7358 7359 : ee: E rr: V + val resumedresumed: ref<global,bool> = (unsafe-ststd/core/hnd/unsafe-st: (f : () -> <st<global>|$7237> ref<global,bool>) -> $7237 (() -> $7237 ref<global,bool>){refstd/core/types/ref: (value : bool) -> <alloc<global>,read<global>,write<global>|$7237> ref<global,bool>(Falsestd/core/types/False: bool)})() + fun kprotectkprotect: (ret : $7236) -> $7237 $7238(retret: $7236)result: -> $7237 $7238 + (unsafe-ststd/core/hnd/unsafe-st: (f : () -> <st<global>|$7237> ()) -> $7237 (() -> $7237 ()){resumedresumed: ref<global,bool> :=std/core/types/set: (ref : ref<global,bool>, assigned : bool) -> <write<global>,alloc<global>,read<global>|$7237> () Truestd/core/types/True: bool})() + kk: (resume-result<$7236,$7238>) -> $7237 $7238(Deepstd/core/hnd/Deep: forall<a,b> (result : a) -> resume-result<a,b>(retret: $7236)) + val resres: $7238 = clauseclause: (x : $7235, k : ($7236) -> $7237 $7238) -> $7237 $7238(xx: $7235,kprotectkprotect: (ret : $7236) -> $7237 $7238) + if yieldingstd/core/hnd/yielding: () -> $7237 bool() returnreturn: $7238 yield-extendstd/core/hnd/yield-extend: (next : ($7238) -> $7237 $7238) -> $7237 $7238( fnfn: (xres : $7238) -> $7237 $7238(xresxres: $7238) protect-checkstd/core/hnd/protect-check: (resumed : ref<global,bool>, k : (resume-result<$7236,$7238>) -> $7237 $7238, res : $7238) -> $7237 $7238(resumedresumed: ref<global,bool>,kk: (resume-result<$7236,$7238>) -> $7237 $7238,xresxres: $7238) )std/core/types/Unit: () + protect-checkstd/core/hnd/protect-check: (resumed : ref<global,bool>, k : (resume-result<$7236,$7238>) -> $7237 $7238, res : $7238) -> $7237 $7238(resumedresumed: ref<global,bool>,kk: (resume-result<$7236,$7238>) -> $7237 $7238,resres: $7238) + +/* +pub fun clause-control1( clause : (x:a, k: b -> e r) -> e r ) : clause1<a,b,e,r> + Clause1(fn(m,w,x){ yield-to(m, fn(k){ clause(x, fn(r){ k({r}) } ) }) }) +*/ + +// generic control clause +pub fun clause-control1std/core/hnd/clause-control1: forall<a,b,e,c,d> (clause : (x : a, k : (b) -> e d) -> e d) -> clause1<a,b,c,e,d>( clauseclause: (x : $7449, k : ($7450) -> $7451 $7453) -> $7451 $7453 : (x:aa: V, k: bb: V -> ee: E rr: V) -> ee: E rr: V )result: -> total clause1<7513,7514,7516,7515,7517> : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<aa: V,bb: V,hh: (E, V) -> V,ee: E,rr: V> + Clause1std/core/hnd/Clause1: forall<a,b,c,e,d> (clause : (marker<e,d>, ev<c>, a) -> e b) -> clause1<a,b,c,e,d>(fnfn: (m : marker<$7451,$7453>, ev<$7452>, x : $7449) -> $7451 $7450(mm: marker<$7451,$7453>,_ev,xx: $7449){ yield-tostd/core/hnd/yield-to: (m : marker<$7451,$7453>, clause : ((resume-result<$7450,$7453>) -> $7451 $7453) -> $7451 $7453) -> $7451 $7450(mm: marker<$7451,$7453>, fnfn: (k : (resume-result<$7450,$7453>) -> $7451 $7453) -> $7451 $7453(kk: (resume-result<$7450,$7453>) -> $7451 $7453) protectstd/core/hnd/protect: (x : $7449, clause : (x : $7449, k : ($7450) -> $7451 $7453) -> $7451 $7453, k : (resume-result<$7450,$7453>) -> $7451 $7453) -> $7451 $7453(xx: $7449,clauseclause: (x : $7449, k : ($7450) -> $7451 $7453) -> $7451 $7453,kk: (resume-result<$7450,$7453>) -> $7451 $7453) ) }) + +// tail-resumptive clause: resumes exactly once at the end +// (these can be executed 'in-place' without capturing a resumption) +pub fun clause-tail1std/core/hnd/clause-tail1: forall<e,a,b,c,d> (op : (c) -> e d) -> clause1<c,d,b,e,a><ee: E,rr: V,hh: (E, V) -> V,aa: V,bb: V>(opop: ($8863) -> $8860 $8864 : aa: V -> ee: E bb: V)result: -> total clause1<8915,8916,8914,8912,8913> : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<aa: V,bb: V,hh: (E, V) -> V,ee: E,rr: V> + Clause1std/core/hnd/Clause1: forall<a,b,c,e,d> (clause : (marker<e,d>, ev<c>, a) -> e b) -> clause1<a,b,c,e,d>(fnfn: (marker<$8860,$8861>, ev : ev<$8862>, x : $8863) -> $8860 $8864(_m,evev: ev<$8862>,xx: $8863){ under1std/core/hnd/under1: (ev : ev<$8862>, op : ($8863) -> $8860 $8864, x : $8863) -> $8860 $8864(evev: ev<$8862>,opop: ($8863) -> $8860 $8864,xx: $8863) }) + +// tail-resumptive clause that does not itself invoke operations +// (these can be executed 'in-place' without setting the correct evidence vector) +pub fun clause-tail-noop1std/core/hnd/clause-tail-noop1: forall<e,a,b,c,d> (op : (c) -> e d) -> clause1<c,d,b,e,a><ee: E,rr: V,hh: (E, V) -> V,aa: V,bb: V>(opop: ($3818) -> $3815 $3819 : aa: V -> ee: E bb: V)result: -> total clause1<3856,3857,3855,3853,3854> : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<aa: V,bb: V,hh: (E, V) -> V,ee: E,rr: V> + Clause1std/core/hnd/Clause1: forall<a,b,c,e,d> (clause : (marker<e,d>, ev<c>, a) -> e b) -> clause1<a,b,c,e,d>(fnfn: (marker<$3815,$3816>, ev<$3817>, x : $3818) -> $3815 $3819(_m,_ev,xx: $3818){ opop: ($3818) -> $3815 $3819(xx: $3818) }) + +// clause that never resumes (e.g. an exception handler) +// (these do not need to capture a resumption and execute finally clauses upfront) +pub fun clause-never1std/core/hnd/clause-never1: forall<a,b,e,c,d> (op : (a) -> e d) -> clause1<a,b,c,e,d>( opop: ($8016) -> $8018 $8020 : aa: V -> ee: E rr: V )result: -> total clause1<8069,8070,8072,8071,8073> : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<aa: V,bb: V,hh: (E, V) -> V,ee: E,rr: V> + Clause1std/core/hnd/Clause1: forall<a,b,c,e,d> (clause : (marker<e,d>, ev<c>, a) -> e b) -> clause1<a,b,c,e,d>(fnfn: (m : marker<$8018,$8020>, ev<$8019>, x : $8016) -> $8018 $8017(mm: marker<$8018,$8020>,_ev,xx: $8016){ yield-to-finalstd/core/hnd/yield-to-final: (m : marker<$8018,$8020>, clause : ((resume-result<$8017,$8020>) -> $8018 $8020) -> $8018 $8020) -> $8018 $8017(mm: marker<$8018,$8020>, fnfn: ((resume-result<$8017,$8020>) -> $8018 $8020) -> $8018 $8020(_k) opop: ($8016) -> $8018 $8020(xx: $8016) ) }) + + +//---------------------------------------------------------------- +// 0 arguments; reuse 1 argument Clauses +//---------------------------------------------------------------- + +abstract value type clause0std/core/hnd/clause0: (V, (E, V) -> V, E, V) -> V<bb: V,hh: (E, V) -> V,ee: E,rr: V> + Clause0std/core/hnd/Clause0: forall<a,b,e,c> (clause : (marker<e,c>, ev<b>) -> e a) -> clause0<a,b,e,c>( clausestd/core/hnd/clause0/clause: forall<a,b,e,c> (clause0 : clause0<a,b,e,c>) -> ((marker<e,c>, ev<b>) -> e a): (markerstd/core/hnd/marker: (E, V) -> V<ee: E,rr: V>, evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>) -> ee: E bb: V ) + + +//inline extern cast-hnd( h : h<e1,r> ) : e h<e,r> { inline "#1"//inline extern cast-marker( m : marker<e1,r> ) : e marker<e,r> { inline "#1" +pub inline fun @perform0( evev: ev<$3060> : evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>, opop: forall<e,a> ($3060<e,a>) -> clause0<$3058,$3060,e,a> : (forall<e1e1: E,rr: V> hh: (E, V) -> V<e1e1: E,rr: V> -> clause0std/core/hnd/clause0: (V, (E, V) -> V, E, V) -> V<bb: V,hh: (E, V) -> V,e1e1: E,rr: V>) )result: -> 3118 3117 : ee: E bb: V + match evev: ev<$3060> + Evstd/core/hnd/Ev: forall<a,e,b> (htag : htag<a>, marker : marker<e,b>, hnd : a<e,b>, hevv : evv<e>) -> ev<a>(_tag,mm: marker<$3063,$3064>,hh: $3060<$3063,$3064>,_w) -> match hh: $3060<$3063,$3064>.opop: ($3060<$3063,$3064>) -> $3059 clause0<$3058,$3060,$3063,$3064> + Clause0std/core/hnd/Clause0: forall<a,b,e,c> (clause : (marker<e,c>, ev<b>) -> e a) -> clause0<a,b,e,c>(ff: (marker<$3063,$3064>, ev<$3060>) -> $3063 $3058) -> cast-clause0std/core/hnd/cast-clause0: (f : (marker<$3063,$3064>, ev<$3060>) -> $3063 $3058) -> $3059 ((marker<$3063,$3064>, ev<$3060>) -> $3059 $3058)(ff: (marker<$3063,$3064>, ev<$3060>) -> $3063 $3058)(mm: marker<$3063,$3064>,evev: ev<$3060>) + +inline fun under0std/core/hnd/under0: forall<a,e,b> (ev : ev<b>, op : () -> e a) -> e a( evev: ev<$8719> : evstd/core/hnd/ev: ((E, V) -> V) -> V<ii: (E, V) -> V>, opop: () -> $8718 $8717 : () -> ee: E bb: V)result: -> 8790 8789 : ee: E bb: V + val w0w0: evv<_8727> = evv-swap-withstd/core/hnd/evv-swap-with: (ev : ev<$8719>) -> $8718 evv<_8727>(evev: ev<$8719>) + val yy: $8717 = opop: () -> $8718 $8717() + // evv-set(w0) // only needed before yielding for evidence expected check in prompt + evv-setstd/core/hnd/evv-set: (w : evv<_8727>) -> $8718 ()(w0w0: evv<_8727>) + if yieldingstd/core/hnd/yielding: () -> $8718 bool() returnreturn: $8717 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $8718 $8717, a) -> $8718 $8717) -> $8718 $8717( fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($8754) -> $8718 $8717,resres: $8754) under1std/core/hnd/under1: (ev : ev<$8719>, op : ($8754) -> $8718 $8717, x : $8754) -> $8718 $8717(evev: ev<$8719>,contcont: ($8754) -> $8718 $8717,resres: $8754) )std/core/types/Unit: () + yy: $8717 + +pub fun clause-control-raw0std/core/hnd/clause-control-raw0: forall<a,e,e1,b,c> (op : (resume-context<a,e,e1,c>) -> e c) -> clause0<a,b,e,c>( opop: (resume-context<$6727,$6728,$6729,$6731>) -> $6728 $6731 : resume-contextstd/core/hnd/resume-context: (V, E, E, V) -> V<bb: V,ee: E,e0e0: E,rr: V> -> ee: E rr: V )result: -> total clause0<6789,6792,6790,6793> : clause0std/core/hnd/clause0: (V, (E, V) -> V, E, V) -> V<bb: V,hh: (E, V) -> V,ee: E,rr: V> + Clause0std/core/hnd/Clause0: forall<a,b,e,c> (clause : (marker<e,c>, ev<b>) -> e a) -> clause0<a,b,e,c>(fnfn: (m : marker<$6728,$6731>, ev<$6730>) -> $6728 $6727(mm: marker<$6728,$6731>,_ev){ yield-tostd/core/hnd/yield-to: (m : marker<$6728,$6731>, clause : ((resume-result<$6727,$6731>) -> $6728 $6731) -> $6728 $6731) -> $6728 $6727(mm: marker<$6728,$6731>, fnfn: (k : (resume-result<$6727,$6731>) -> $6728 $6731) -> $6728 $6731(kk: (resume-result<$6727,$6731>) -> $6728 $6731){ opop: (resume-context<$6727,$6728,$6729,$6731>) -> $6728 $6731(Resume-contextstd/core/hnd/Resume-context: forall<a,e,e1,b> (k : (resume-result<a,b>) -> e b) -> resume-context<a,e,e1,b>(kk: (resume-result<$6727,$6731>) -> $6728 $6731)) } ) }) + +/* +pub fun clause-control0( op : (b -> e r) -> e r ) : clause0<b,e,r> + Clause0(fn(m,w){ yield-to(m, fn(k){ op(fn(r){ k({r} )}) }) }) +*/ + +pub fun clause-control0std/core/hnd/clause-control0: forall<a,e,b,c> (op : ((a) -> e c) -> e c) -> clause0<a,b,e,c>( opop: (($7372) -> $7373 $7375) -> $7373 $7375 : (bb: V -> ee: E rr: V) -> ee: E rr: V )result: -> total clause0<7432,7434,7433,7435> : clause0std/core/hnd/clause0: (V, (E, V) -> V, E, V) -> V<bb: V,hh: (E, V) -> V,ee: E,rr: V> + Clause0std/core/hnd/Clause0: forall<a,b,e,c> (clause : (marker<e,c>, ev<b>) -> e a) -> clause0<a,b,e,c>(fnfn: (m : marker<$7373,$7375>, ev<$7374>) -> $7373 $7372(mm: marker<$7373,$7375>,_ev){ yield-tostd/core/hnd/yield-to: (m : marker<$7373,$7375>, clause : ((resume-result<$7372,$7375>) -> $7373 $7375) -> $7373 $7375) -> $7373 $7372(mm: marker<$7373,$7375>, fnfn: (k : (resume-result<$7372,$7375>) -> $7373 $7375) -> $7373 $7375(kk: (resume-result<$7372,$7375>) -> $7373 $7375){ protectstd/core/hnd/protect: (x : (), clause : (x : (), k : ($7372) -> $7373 $7375) -> $7373 $7375, k : (resume-result<$7372,$7375>) -> $7373 $7375) -> $7373 $7375((std/core/types/Unit: ())std/core/types/Unit: (),fnfn: ((), r : ($7372) -> $7373 $7375) -> $7373 $7375(_x,rr: ($7372) -> $7373 $7375){ opop: (($7372) -> $7373 $7375) -> $7373 $7375(rr: ($7372) -> $7373 $7375) }, kk: (resume-result<$7372,$7375>) -> $7373 $7375) }) }) + + +pub fun clause-tail0std/core/hnd/clause-tail0: forall<e,a,b,c> (op : () -> e c) -> clause0<c,b,e,a><ee: E,rr: V,hh: (E, V) -> V,bb: V>(opop: () -> $8801 $8804 : () -> ee: E bb: V)result: -> total clause0<8846,8845,8843,8844> : clause0std/core/hnd/clause0: (V, (E, V) -> V, E, V) -> V<bb: V,hh: (E, V) -> V,ee: E,rr: V> + Clause0std/core/hnd/Clause0: forall<a,b,e,c> (clause : (marker<e,c>, ev<b>) -> e a) -> clause0<a,b,e,c>(fnfn: (marker<$8801,$8802>, ev : ev<$8803>) -> $8801 $8804(_m,evev: ev<$8803>){ under0std/core/hnd/under0: (ev : ev<$8803>, op : () -> $8801 $8804) -> $8801 $8804(evev: ev<$8803>,opop: () -> $8801 $8804) }) + +pub fun clause-tail-noop0std/core/hnd/clause-tail-noop0: forall<e,a,b,c> (op : () -> e c) -> clause0<c,b,e,a><ee: E,rr: V,hh: (E, V) -> V,bb: V>(opop: () -> $3767 $3770 : () -> ee: E bb: V)result: -> total clause0<3801,3800,3798,3799> : clause0std/core/hnd/clause0: (V, (E, V) -> V, E, V) -> V<bb: V,hh: (E, V) -> V,ee: E,rr: V> + Clause0std/core/hnd/Clause0: forall<a,b,e,c> (clause : (marker<e,c>, ev<b>) -> e a) -> clause0<a,b,e,c>(fnfn: (marker<$3767,$3768>, ev<$3769>) -> $3767 $3770(_m,_ev){ opop: () -> $3767 $3770() }) + +pub fun clause-valuestd/core/hnd/clause-value: forall<a,e,b,c> (v : a) -> clause0<a,b,e,c>(vv: $3981 : bb: V)result: -> total clause0<4012,4014,4013,4015> : clause0std/core/hnd/clause0: (V, (E, V) -> V, E, V) -> V<bb: V,hh: (E, V) -> V,ee: E,rr: V> + Clause0std/core/hnd/Clause0: forall<a,b,e,c> (clause : (marker<e,c>, ev<b>) -> e a) -> clause0<a,b,e,c>(fnfn: (marker<$3982,$3984>, ev<$3983>) -> $3982 $3981(_m,_ev){ vv: $3981 }) + +pub fun clause-never0std/core/hnd/clause-never0: forall<a,e,b,c> (op : () -> e c) -> clause0<a,b,e,c>( opop: () -> $7954 $7956 : () -> ee: E rr: V )result: -> total clause0<7999,8001,8000,8002> : clause0std/core/hnd/clause0: (V, (E, V) -> V, E, V) -> V<bb: V,hh: (E, V) -> V,ee: E,rr: V> + Clause0std/core/hnd/Clause0: forall<a,b,e,c> (clause : (marker<e,c>, ev<b>) -> e a) -> clause0<a,b,e,c>(fnfn: (m : marker<$7954,$7956>, ev<$7955>) -> $7954 $7953(mm: marker<$7954,$7956>,_ev){ yield-to-finalstd/core/hnd/yield-to-final: (m : marker<$7954,$7956>, clause : ((resume-result<$7953,$7956>) -> $7954 $7956) -> $7954 $7956) -> $7954 $7953(mm: marker<$7954,$7956>, fnfn: ((resume-result<$7953,$7956>) -> $7954 $7956) -> $7954 $7956(_k){ opop: () -> $7954 $7956() }) }) + +//---------------------------------------------------------------- +// 2 arguments +//---------------------------------------------------------------- + +abstract value type clause2std/core/hnd/clause2: (V, V, V, (E, V) -> V, E, V) -> V<a1a1: V,a2a2: V,bb: V,hh: (E, V) -> V,ee: E,rr: V> + Clause2std/core/hnd/Clause2: forall<a,b,c,d,e,a1> (clause : (marker<e,a1>, ev<d>, a, b) -> e c) -> clause2<a,b,c,d,e,a1>( clausestd/core/hnd/clause2/clause: forall<a,b,c,d,e,a1> (clause2 : clause2<a,b,c,d,e,a1>) -> ((marker<e,a1>, ev<d>, a, b) -> e c): (markerstd/core/hnd/marker: (E, V) -> V<ee: E,rr: V>, evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>, a1a1: V, a2a2: V) -> ee: E bb: V ) + +fun under2std/core/hnd/under2: forall<a,b,c,e,d> (ev : ev<d>, op : (a, b) -> e c, x1 : a, x2 : b) -> e c( evev: ev<$8937> : evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>, opop: ($8933, $8934) -> $8936 $8935 : (a1a1: V,a2a2: V) -> ee: E bb: V, x1x1: $8933 : a1a1: V, x2x2: $8934 : a2a2: V )result: -> 9016 9015 : ee: E bb: V + val w0w0: evv<_8945> = evv-swap-withstd/core/hnd/evv-swap-with: (ev : ev<$8937>) -> $8936 evv<_8945>(evev: ev<$8937>) + val zz: $8935 = opop: ($8933, $8934) -> $8936 $8935(x1x1: $8933,x2x2: $8934) + evv-setstd/core/hnd/evv-set: (w : evv<_8945>) -> $8936 ()(w0w0: evv<_8945>) + if yieldingstd/core/hnd/yielding: () -> $8936 bool() returnreturn: $8935 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $8936 $8935, a) -> $8936 $8935) -> $8936 $8935( fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($8974) -> $8936 $8935,resres: $8974) under1std/core/hnd/under1: (ev : ev<$8937>, op : ($8974) -> $8936 $8935, x : $8974) -> $8936 $8935(evev: ev<$8937>,contcont: ($8974) -> $8936 $8935,resres: $8974) )std/core/types/Unit: () + zz: $8935 + +fun protect2std/core/hnd/protect2: forall<a,b,c,e,d> (x1 : a, x2 : b, clause : (x : a, x : b, k : (c) -> e d) -> e d, k : (resume-result<c,d>) -> e d) -> e d( x1x1: $7534 : a1a1: V, x2x2: $7535:a2a2: V, clauseclause: (x : $7534, x : $7535, k : ($7536) -> $7537 $7538) -> $7537 $7538 : (x:a1a1: V,x:a2a2: V, k: bb: V -> ee: E rr: V) -> ee: E rr: V, kk: (resume-result<$7536,$7538>) -> $7537 $7538 : resume-resultstd/core/hnd/resume-result: (V, V) -> V<bb: V,rr: V> -> ee: E rr: V )result: -> 7662 7663 : ee: E rr: V + val resumedresumed: ref<global,bool> = (unsafe-ststd/core/hnd/unsafe-st: (f : () -> <st<global>|$7537> ref<global,bool>) -> $7537 (() -> $7537 ref<global,bool>){refstd/core/types/ref: (value : bool) -> <alloc<global>,read<global>,write<global>|$7537> ref<global,bool>(Falsestd/core/types/False: bool)})() + fun kprotectkprotect: (ret : $7536) -> $7537 $7538(retret: $7536)result: -> $7537 $7538 + (unsafe-ststd/core/hnd/unsafe-st: (f : () -> <st<global>|$7537> ()) -> $7537 (() -> $7537 ()){ resumedresumed: ref<global,bool> :=std/core/types/set: (ref : ref<global,bool>, assigned : bool) -> <write<global>,alloc<global>,read<global>|$7537> () Truestd/core/types/True: bool })() + kk: (resume-result<$7536,$7538>) -> $7537 $7538(Deepstd/core/hnd/Deep: forall<a,b> (result : a) -> resume-result<a,b>(retret: $7536)) + val resres: $7538 = clauseclause: (x : $7534, x : $7535, k : ($7536) -> $7537 $7538) -> $7537 $7538(x1x1: $7534,x2x2: $7535,kprotectkprotect: (ret : $7536) -> $7537 $7538) + if yieldingstd/core/hnd/yielding: () -> $7537 bool() returnreturn: $7538 yield-extendstd/core/hnd/yield-extend: (next : ($7538) -> $7537 $7538) -> $7537 $7538( fnfn: (xres : $7538) -> $7537 $7538(xresxres: $7538) protect-checkstd/core/hnd/protect-check: (resumed : ref<global,bool>, k : (resume-result<$7536,$7538>) -> $7537 $7538, res : $7538) -> $7537 $7538(resumedresumed: ref<global,bool>,kk: (resume-result<$7536,$7538>) -> $7537 $7538,xresxres: $7538) )std/core/types/Unit: () + protect-checkstd/core/hnd/protect-check: (resumed : ref<global,bool>, k : (resume-result<$7536,$7538>) -> $7537 $7538, res : $7538) -> $7537 $7538(resumedresumed: ref<global,bool>,kk: (resume-result<$7536,$7538>) -> $7537 $7538,resres: $7538) + +pub fun clause-control2std/core/hnd/clause-control2: forall<a,b,c,e,d,a1> (clause : (x1 : a, x2 : b, k : (c) -> e a1) -> e a1) -> clause2<a,b,c,d,e,a1>( clauseclause: (x1 : $7679, x2 : $7680, k : ($7681) -> $7682 $7684) -> $7682 $7684 : (x1:a1a1: V, x2:a2a2: V, k: bb: V -> ee: E rr: V) -> ee: E rr: V )result: -> total clause2<7753,7754,7755,7757,7756,7758> : clause2std/core/hnd/clause2: (V, V, V, (E, V) -> V, E, V) -> V<a1a1: V,a2a2: V,bb: V,hh: (E, V) -> V,ee: E,rr: V> + Clause2std/core/hnd/Clause2: forall<a,b,c,d,e,a1> (clause : (marker<e,a1>, ev<d>, a, b) -> e c) -> clause2<a,b,c,d,e,a1>(fnfn: (m : marker<$7682,$7684>, ev<$7683>, x1 : $7679, x2 : $7680) -> $7682 $7681(mm: marker<$7682,$7684>,_ev,x1x1: $7679,x2x2: $7680){ yield-tostd/core/hnd/yield-to: (m : marker<$7682,$7684>, clause : ((resume-result<$7681,$7684>) -> $7682 $7684) -> $7682 $7684) -> $7682 $7681(mm: marker<$7682,$7684>, fnfn: (k : (resume-result<$7681,$7684>) -> $7682 $7684) -> $7682 $7684(kk: (resume-result<$7681,$7684>) -> $7682 $7684){ protect2std/core/hnd/protect2: (x1 : $7679, x2 : $7680, clause : (x : $7679, x : $7680, k : ($7681) -> $7682 $7684) -> $7682 $7684, k : (resume-result<$7681,$7684>) -> $7682 $7684) -> $7682 $7684(x1x1: $7679,x2x2: $7680,clauseclause: (x1 : $7679, x2 : $7680, k : ($7681) -> $7682 $7684) -> $7682 $7684,kk: (resume-result<$7681,$7684>) -> $7682 $7684) }) }) + + +pub fun clause-control-raw2std/core/hnd/clause-control-raw2: forall<a,b,c,e,e1,d,a1> (op : (x1 : a, x2 : b, r : resume-context<c,e,e1,a1>) -> e a1) -> clause2<a,b,c,d,e,a1>( opop: (x1 : $6904, x2 : $6905, r : resume-context<$6906,$6907,$6908,$6910>) -> $6907 $6910 : (x1:a1a1: V, x2:a2a2: V, r: resume-contextstd/core/hnd/resume-context: (V, E, E, V) -> V<bb: V,ee: E,e0e0: E,rr: V>) -> ee: E rr: V )result: -> total clause2<6980,6981,6982,6985,6983,6986> : clause2std/core/hnd/clause2: (V, V, V, (E, V) -> V, E, V) -> V<a1a1: V,a2a2: V,bb: V,hh: (E, V) -> V,ee: E,rr: V> + Clause2std/core/hnd/Clause2: forall<a,b,c,d,e,a1> (clause : (marker<e,a1>, ev<d>, a, b) -> e c) -> clause2<a,b,c,d,e,a1>(fnfn: (m : marker<$6907,$6910>, ev<$6909>, x1 : $6904, x2 : $6905) -> $6907 $6906(mm: marker<$6907,$6910>,_ev,x1x1: $6904,x2x2: $6905){ yield-tostd/core/hnd/yield-to: (m : marker<$6907,$6910>, clause : ((resume-result<$6906,$6910>) -> $6907 $6910) -> $6907 $6910) -> $6907 $6906(mm: marker<$6907,$6910>, fnfn: (k : (resume-result<$6906,$6910>) -> $6907 $6910) -> $6907 $6910(kk: (resume-result<$6906,$6910>) -> $6907 $6910){ opop: (x1 : $6904, x2 : $6905, r : resume-context<$6906,$6907,$6908,$6910>) -> $6907 $6910(x1x1: $6904,x2x2: $6905,Resume-contextstd/core/hnd/Resume-context: forall<a,e,e1,b> (k : (resume-result<a,b>) -> e b) -> resume-context<a,e,e1,b>(kk: (resume-result<$6906,$6910>) -> $6907 $6910)) } ) }) + +pub fun clause-tail2std/core/hnd/clause-tail2: forall<e,a,b,c,d,a1> (op : (c, d) -> e a1) -> clause2<c,d,a1,b,e,a><ee: E,rr: V,hh: (E, V) -> V,a1a1: V,a2a2: V,bb: V>(opop: ($9036, $9037) -> $9033 $9038 : (a1a1: V,a2a2: V) -> ee: E bb: V)result: -> total clause2<9098,9099,9100,9097,9095,9096> : clause2std/core/hnd/clause2: (V, V, V, (E, V) -> V, E, V) -> V<a1a1: V,a2a2: V,bb: V,hh: (E, V) -> V,ee: E,rr: V> + Clause2std/core/hnd/Clause2: forall<a,b,c,d,e,a1> (clause : (marker<e,a1>, ev<d>, a, b) -> e c) -> clause2<a,b,c,d,e,a1>(fnfn: (m : marker<$9033,$9034>, ev : ev<$9035>, x1 : $9036, x2 : $9037) -> $9033 $9038(mm: marker<$9033,$9034>,evev: ev<$9035>,x1x1: $9036,x2x2: $9037){ under2std/core/hnd/under2: (ev : ev<$9035>, op : ($9036, $9037) -> $9033 $9038, x1 : $9036, x2 : $9037) -> $9033 $9038(evev: ev<$9035>,opop: ($9036, $9037) -> $9033 $9038,x1x1: $9036,x2x2: $9037) }) + +pub fun clause-tail-noop2std/core/hnd/clause-tail-noop2: forall<e,a,b,c,d,a1> (op : (c, d) -> e a1) -> clause2<c,d,a1,b,e,a><ee: E,rr: V,hh: (E, V) -> V,a1a1: V,a2a2: V,bb: V>(opop: ($3877, $3878) -> $3874 $3879 : (a1a1: V,a2a2: V) -> ee: E bb: V)result: -> total clause2<3922,3923,3924,3921,3919,3920> : clause2std/core/hnd/clause2: (V, V, V, (E, V) -> V, E, V) -> V<a1a1: V,a2a2: V,bb: V,hh: (E, V) -> V,ee: E,rr: V> + Clause2std/core/hnd/Clause2: forall<a,b,c,d,e,a1> (clause : (marker<e,a1>, ev<d>, a, b) -> e c) -> clause2<a,b,c,d,e,a1>(fnfn: (marker<$3874,$3875>, ev<$3876>, x1 : $3877, x2 : $3878) -> $3874 $3879(_m,_ev,x1x1: $3877,x2x2: $3878){ opop: ($3877, $3878) -> $3874 $3879(x1x1: $3877,x2x2: $3878) }) + +pub inline fun @perform2( evxevx: ev<$3220> : evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>, opop: forall<e,a> ($3220<e,a>) -> clause2<$3216,$3217,$3218,$3220,e,a> : (forall<e1e1: E,rr: V> hh: (E, V) -> V<e1e1: E,rr: V> -> clause2std/core/hnd/clause2: (V, V, V, (E, V) -> V, E, V) -> V<aa: V,bb: V,cc: V,hh: (E, V) -> V,e1e1: E,rr: V>), xx: $3216 : aa: V, yy: $3217 : bb: V )result: -> 3294 3293 : ee: E cc: V + match evxevx: ev<$3220> + Evstd/core/hnd/Ev: forall<a,e,b> (htag : htag<a>, marker : marker<e,b>, hnd : a<e,b>, hevv : evv<e>) -> ev<a>(_tag,mm: marker<$3223,$3224>,hh: $3220<$3223,$3224>,_w) -> match hh: $3220<$3223,$3224>.opop: ($3220<$3223,$3224>) -> $3219 clause2<$3216,$3217,$3218,$3220,$3223,$3224> + Clause2std/core/hnd/Clause2: forall<a,b,c,d,e,a1> (clause : (marker<e,a1>, ev<d>, a, b) -> e c) -> clause2<a,b,c,d,e,a1>(ff: (marker<$3223,$3224>, ev<$3220>, $3216, $3217) -> $3223 $3218) -> cast-clause2std/core/hnd/cast-clause2: (f : (marker<$3223,$3224>, ev<$3220>, $3216, $3217) -> $3223 $3218) -> $3219 ((marker<$3223,$3224>, ev<$3220>, $3216, $3217) -> $3219 $3218)(ff: (marker<$3223,$3224>, ev<$3220>, $3216, $3217) -> $3223 $3218)(mm: marker<$3223,$3224>,evxevx: ev<$3220>,xx: $3216,yy: $3217) + +pub fun clause-never2std/core/hnd/clause-never2: forall<a,b,c,e,d,a1> (op : (a, b) -> e a1) -> clause2<a,b,c,d,e,a1>( opop: ($8090, $8091) -> $8093 $8095 : (a1a1: V,a2a2: V) -> ee: E rr: V )result: -> total clause2<8150,8151,8152,8154,8153,8155> : clause2std/core/hnd/clause2: (V, V, V, (E, V) -> V, E, V) -> V<a1a1: V,a2a2: V,bb: V,hh: (E, V) -> V,ee: E,rr: V> + Clause2std/core/hnd/Clause2: forall<a,b,c,d,e,a1> (clause : (marker<e,a1>, ev<d>, a, b) -> e c) -> clause2<a,b,c,d,e,a1>(fnfn: (m : marker<$8093,$8095>, ev<$8094>, x1 : $8090, x2 : $8091) -> $8093 $8092(mm: marker<$8093,$8095>,_ev,x1x1: $8090,x2x2: $8091){ yield-to-finalstd/core/hnd/yield-to-final: (m : marker<$8093,$8095>, clause : ((resume-result<$8092,$8095>) -> $8093 $8095) -> $8093 $8095) -> $8093 $8092(mm: marker<$8093,$8095>, fnfn: ((resume-result<$8092,$8095>) -> $8093 $8095) -> $8093 $8095(_k){ opop: ($8090, $8091) -> $8093 $8095(x1x1: $8090,x2x2: $8091) }) }) + + +//---------------------------------------------------------------- +// 3 arguments: reuse 1 argument clause. +// Or should the compiler do tupling/untupling? +//---------------------------------------------------------------- + +// For interal use +fun xperform1std/core/hnd/xperform1: forall<a,b,e,c> (ev : ev<c>, op : forall<e1,d> (c<e1,d>) -> clause1<a,b,c,e1,d>, x : a) -> e b( evev: ev<$3638> : evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>, opop: forall<e,a> ($3638<e,a>) -> clause1<$3635,$3636,$3638,e,a> : (forall<e1e1: E,rr: V> hh: (E, V) -> V<e1e1: E,rr: V> -> clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<aa: V,bb: V,hh: (E, V) -> V,e1e1: E,rr: V>), xx: $3635 : aa: V )result: -> 3704 3703 : ee: E bb: V + match evev: ev<$3638> + Evstd/core/hnd/Ev: forall<a,e,b> (htag : htag<a>, marker : marker<e,b>, hnd : a<e,b>, hevv : evv<e>) -> ev<a>(_tag,mm: marker<$3641,$3642>,hh: $3638<$3641,$3642>,_w) -> match hh: $3638<$3641,$3642>.opop: ($3638<$3641,$3642>) -> $3637 clause1<$3635,$3636,$3638,$3641,$3642> + Clause1std/core/hnd/Clause1: forall<a,b,c,e,d> (clause : (marker<e,d>, ev<c>, a) -> e b) -> clause1<a,b,c,e,d>(ff: (marker<$3641,$3642>, ev<$3638>, $3635) -> $3641 $3636) -> cast-clause1std/core/hnd/cast-clause1: (f : (marker<$3641,$3642>, ev<$3638>, $3635) -> $3641 $3636) -> $3637 ((marker<$3641,$3642>, ev<$3638>, $3635) -> $3637 $3636)(ff: (marker<$3641,$3642>, ev<$3638>, $3635) -> $3641 $3636)(mm: marker<$3641,$3642>,evev: ev<$3638>,xx: $3635) + +pub fun clause-control-raw3std/core/hnd/clause-control-raw3: forall<a,b,c,d,e,e1,a1,b1> (op : (x1 : a, x2 : b, x3 : c, r : resume-context<d,e,e1,b1>) -> e b1) -> clause1<(a, b, c),d,a1,e,b1>( opop: (x1 : $7009, x2 : $7010, x3 : $7011, r : resume-context<$7012,$7013,$7014,$7016>) -> $7013 $7016 : (x1:a1a1: V, x2:a2a2: V, x3:a3a3: V, r: resume-contextstd/core/hnd/resume-context: (V, E, E, V) -> V<bb: V,ee: E,e0e0: E,rr: V>) -> ee: E rr: V )result: -> total clause1<(7069, 7070, 7071),7072,7075,7073,7076> : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<(std/core/types/tuple3: (V, V, V) -> Va1a1: V,a2a2: V,a3a3: V),bb: V,hh: (E, V) -> V,ee: E,rr: V> + clause-control-raw1std/core/hnd/clause-control-raw1: (op : (x : ($7009, $7010, $7011), r : resume-context<$7012,$7013,$7014,$7016>) -> $7013 $7016) -> clause1<($7009, $7010, $7011),$7012,$7015,$7013,$7016>( fnfn: (($7009, $7010, $7011), r : resume-context<$7012,$7013,$7014,$7016>) -> $7013 $7016((std/core/types/Tuple3: forall<a,b,c> (fst : a, snd : b, thd : c) -> (a, b, c)x1x1: $7009,x2x2: $7010,x3x3: $7011)std/core/types/Tuple3: forall<a,b,c> (fst : a, snd : b, thd : c) -> (a, b, c),rr: resume-context<$7012,$7013,$7014,$7016>){ opop: (x1 : $7009, x2 : $7010, x3 : $7011, r : resume-context<$7012,$7013,$7014,$7016>) -> $7013 $7016(x1x1: $7009,x2x2: $7010,x3x3: $7011,rr: resume-context<$7012,$7013,$7014,$7016>) } ) + +pub fun clause-control3std/core/hnd/clause-control3: forall<a,b,c,d,e,a1,b1> (op : (x1 : a, x2 : b, x3 : c, k : (d) -> e b1) -> e b1) -> clause1<(a, b, c),d,a1,e,b1>( opop: (x1 : $7778, x2 : $7779, x3 : $7780, k : ($7781) -> $7782 $7784) -> $7782 $7784 : (x1:a1a1: V, x2:a2a2: V, x3:a3a3: V, k: bb: V -> ee: E rr: V) -> ee: E rr: V )result: -> total clause1<(7832, 7833, 7834),7835,7837,7836,7838> : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<(std/core/types/tuple3: (V, V, V) -> Va1a1: V,a2a2: V,a3a3: V),bb: V,hh: (E, V) -> V,ee: E,rr: V> + clause-control1std/core/hnd/clause-control1: (clause : (x : ($7778, $7779, $7780), k : ($7781) -> $7782 $7784) -> $7782 $7784) -> clause1<($7778, $7779, $7780),$7781,$7783,$7782,$7784>( fnfn: (($7778, $7779, $7780), k : ($7781) -> $7782 $7784) -> $7782 $7784((std/core/types/Tuple3: forall<a,b,c> (fst : a, snd : b, thd : c) -> (a, b, c)x1x1: $7778,x2x2: $7779,x3x3: $7780)std/core/types/Tuple3: forall<a,b,c> (fst : a, snd : b, thd : c) -> (a, b, c),kk: ($7781) -> $7782 $7784){ opop: (x1 : $7778, x2 : $7779, x3 : $7780, k : ($7781) -> $7782 $7784) -> $7782 $7784(x1x1: $7778,x2x2: $7779,x3x3: $7780,kk: ($7781) -> $7782 $7784) } ) + +pub fun clause-tail3std/core/hnd/clause-tail3: forall<e,a,b,c,d,a1,b1> (op : (c, d, a1) -> e b1) -> clause1<(c, d, a1),b1,b,e,a><ee: E,rr: V,hh: (E, V) -> V,a1a1: V,a2a2: V,a3a3: V,bb: V>(opop: ($9123, $9124, $9125) -> $9120 $9126 : (a1a1: V,a2a2: V,a3a3: V) -> ee: E bb: V)result: -> total clause1<(9176, 9177, 9178),9179,9175,9173,9174> : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<(std/core/types/tuple3: (V, V, V) -> Va1a1: V,a2a2: V,a3a3: V),bb: V,hh: (E, V) -> V,ee: E,rr: V> + clause-tail1std/core/hnd/clause-tail1: (op : (($9123, $9124, $9125)) -> $9120 $9126) -> clause1<($9123, $9124, $9125),$9126,$9122,$9120,$9121>( fnfn: (($9123, $9124, $9125)) -> $9120 $9126((std/core/types/Tuple3: forall<a,b,c> (fst : a, snd : b, thd : c) -> (a, b, c)x1x1: $9123,x2x2: $9124,x3x3: $9125)std/core/types/Tuple3: forall<a,b,c> (fst : a, snd : b, thd : c) -> (a, b, c) ){ opop: ($9123, $9124, $9125) -> $9120 $9126(x1x1: $9123,x2x2: $9124,x3x3: $9125) } ) + +pub fun clause-tail-noop3std/core/hnd/clause-tail-noop3: forall<e,a,b,c,d,a1,b1> (op : (c, d, a1) -> e b1) -> clause1<(c, d, a1),b1,b,e,a><ee: E,rr: V,hh: (E, V) -> V,a1a1: V,a2a2: V,a3a3: V,bb: V>(opop: ($8351, $8352, $8353) -> $8348 $8354 : (a1a1: V,a2a2: V,a3a3: V) -> ee: E bb: V)result: -> total clause1<(8404, 8405, 8406),8407,8403,8401,8402> : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<(std/core/types/tuple3: (V, V, V) -> Va1a1: V,a2a2: V,a3a3: V),bb: V,hh: (E, V) -> V,ee: E,rr: V> + clause-tail-noop1std/core/hnd/clause-tail-noop1: (op : (($8351, $8352, $8353)) -> $8348 $8354) -> clause1<($8351, $8352, $8353),$8354,$8350,$8348,$8349>( fnfn: (($8351, $8352, $8353)) -> $8348 $8354((std/core/types/Tuple3: forall<a,b,c> (fst : a, snd : b, thd : c) -> (a, b, c)x1x1: $8351,x2x2: $8352,x3x3: $8353)std/core/types/Tuple3: forall<a,b,c> (fst : a, snd : b, thd : c) -> (a, b, c)){ opop: ($8351, $8352, $8353) -> $8348 $8354(x1x1: $8351,x2x2: $8352,x3x3: $8353) } ) + +pub fun clause-never3std/core/hnd/clause-never3: forall<a,b,c,d,e,a1,b1> (op : (a, b, c) -> e b1) -> clause1<(a, b, c),d,a1,e,b1>( opop: ($8175, $8176, $8177) -> $8179 $8181 : (a1a1: V,a2a2: V,a3a3: V) -> ee: E rr: V )result: -> total clause1<(8228, 8229, 8230),8231,8233,8232,8234> : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<(std/core/types/tuple3: (V, V, V) -> Va1a1: V,a2a2: V,a3a3: V),bb: V,hh: (E, V) -> V,ee: E,rr: V> + clause-never1std/core/hnd/clause-never1: (op : (($8175, $8176, $8177)) -> $8179 $8181) -> clause1<($8175, $8176, $8177),$8178,$8180,$8179,$8181>(fnfn: (($8175, $8176, $8177)) -> $8179 $8181((std/core/types/Tuple3: forall<a,b,c> (fst : a, snd : b, thd : c) -> (a, b, c)x1x1: $8175,x2x2: $8176,x3x3: $8177)std/core/types/Tuple3: forall<a,b,c> (fst : a, snd : b, thd : c) -> (a, b, c)){ opop: ($8175, $8176, $8177) -> $8179 $8181(x1x1: $8175,x2x2: $8176,x3x3: $8177) } ) + +pub fun @perform3( evev: ev<$6481> : evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>, opop: forall<e,a> ($6481<e,a>) -> clause1<($6476, $6477, $6478),$6479,$6481,e,a> : (forall<e1e1: E,rr: V> hh: (E, V) -> V<e1e1: E,rr: V> -> clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<(std/core/types/tuple3: (V, V, V) -> Va1a1: V,a2a2: V,a3a3: V),bb: V,hh: (E, V) -> V,e1e1: E,rr: V>), x1x1: $6476 : a1a1: V, x2x2: $6477 : a2a2: V, x3x3: $6478 : a3a3: V )result: -> 6547 6546 : ee: E bb: V + xperform1std/core/hnd/xperform1: (ev : ev<$6481>, op : forall<e,a> ($6481<e,a>) -> clause1<($6476, $6477, $6478),$6479,$6481,e,a>, x : ($6476, $6477, $6478)) -> $6480 $6479(evev: ev<$6481>,opop: forall<e,a> ($6481<e,a>) -> clause1<($6476, $6477, $6478),$6479,$6481,e,a>,(std/core/types/Tuple3: forall<a,b,c> (fst : a, snd : b, thd : c) -> (a, b, c)x1x1: $6476,x2x2: $6477,x3x3: $6478)std/core/types/Tuple3: forall<a,b,c> (fst : a, snd : b, thd : c) -> (a, b, c)) + +fun under3std/core/hnd/under3: forall<a,b,c,d,e,a1> (ev : ev<a1>, op : (a, b, c) -> e d, x1 : a, x2 : b, x3 : c) -> e d( evev: ev<$9971> : evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>, opop: ($9966, $9967, $9968) -> $9970 $9969 : (a1a1: V,a2a2: V,a3a3: V) -> ee: E bb: V, x1x1: $9966 : a1a1: V, x2x2: $9967 : a2a2: V, x3x3: $9968 : a3a3: V )result: -> 10054 10053 : ee: E bb: V + val w0w0: evv<_9979> = evv-swap-withstd/core/hnd/evv-swap-with: (ev : ev<$9971>) -> $9970 evv<_9979>(evev: ev<$9971>) + val zz: $9969 = opop: ($9966, $9967, $9968) -> $9970 $9969(x1x1: $9966,x2x2: $9967,x3x3: $9968) + evv-setstd/core/hnd/evv-set: (w : evv<_9979>) -> $9970 ()(w0w0: evv<_9979>) + if yieldingstd/core/hnd/yielding: () -> $9970 bool() returnreturn: $9969 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $9970 $9969, a) -> $9970 $9969) -> $9970 $9969( fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($10009) -> $9970 $9969,resres: $10009) under1std/core/hnd/under1: (ev : ev<$9971>, op : ($10009) -> $9970 $9969, x : $10009) -> $9970 $9969(evev: ev<$9971>,contcont: ($10009) -> $9970 $9969,resres: $10009) )std/core/types/Unit: () + zz: $9969 + + + +pub fun clause-control4std/core/hnd/clause-control4: forall<a,b,c,d,a1,e,b1,c1> (op : (x1 : a, x2 : b, x3 : c, x4 : d, k : (a1) -> e c1) -> e c1) -> clause1<(a, b, c, d),a1,b1,e,c1>( opop: (x1 : $7861, x2 : $7862, x3 : $7863, x4 : $7864, k : ($7865) -> $7866 $7868) -> $7866 $7868 : (x1:a1a1: V, x2:a2a2: V, x3:a3a3: V, x4:a4a4: V, k: bb: V -> ee: E rr: V) -> ee: E rr: V )result: -> total clause1<(7920, 7921, 7922, 7923),7924,7926,7925,7927> : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<(std/core/types/tuple4: (V, V, V, V) -> Va1a1: V,a2a2: V,a3a3: V,a4a4: V),bb: V,hh: (E, V) -> V,ee: E,rr: V> + clause-control1std/core/hnd/clause-control1: (clause : (x : ($7861, $7862, $7863, $7864), k : ($7865) -> $7866 $7868) -> $7866 $7868) -> clause1<($7861, $7862, $7863, $7864),$7865,$7867,$7866,$7868>( fnfn: (($7861, $7862, $7863, $7864), k : ($7865) -> $7866 $7868) -> $7866 $7868((std/core/types/Tuple4: forall<a,b,c,d> (fst : a, snd : b, thd : c, field4 : d) -> (a, b, c, d)x1x1: $7861,x2x2: $7862,x3x3: $7863,x4x4: $7864)std/core/types/Tuple4: forall<a,b,c,d> (fst : a, snd : b, thd : c, field4 : d) -> (a, b, c, d),kk: ($7865) -> $7866 $7868){ opop: (x1 : $7861, x2 : $7862, x3 : $7863, x4 : $7864, k : ($7865) -> $7866 $7868) -> $7866 $7868(x1x1: $7861,x2x2: $7862,x3x3: $7863,x4x4: $7864,kk: ($7865) -> $7866 $7868) } ) + +pub fun clause-tail4std/core/hnd/clause-tail4: forall<e,a,b,c,d,a1,b1,c1> (op : (c, d, a1, b1) -> e c1) -> clause1<(c, d, a1, b1),c1,b,e,a><ee: E,rr: V,hh: (E, V) -> V,a1a1: V,a2a2: V,a3a3: V,a4a4: V,bb: V>(opop: ($9205, $9206, $9207, $9208) -> $9202 $9209 : (a1a1: V,a2a2: V,a3a3: V,a4a4: V) -> ee: E bb: V)result: -> total clause1<(9263, 9264, 9265, 9266),9267,9262,9260,9261> : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<(std/core/types/tuple4: (V, V, V, V) -> Va1a1: V,a2a2: V,a3a3: V,a4a4: V),bb: V,hh: (E, V) -> V,ee: E,rr: V> + clause-tail1std/core/hnd/clause-tail1: (op : (($9205, $9206, $9207, $9208)) -> $9202 $9209) -> clause1<($9205, $9206, $9207, $9208),$9209,$9204,$9202,$9203>( fnfn: (($9205, $9206, $9207, $9208)) -> $9202 $9209((std/core/types/Tuple4: forall<a,b,c,d> (fst : a, snd : b, thd : c, field4 : d) -> (a, b, c, d)x1x1: $9205,x2x2: $9206,x3x3: $9207,x4x4: $9208)std/core/types/Tuple4: forall<a,b,c,d> (fst : a, snd : b, thd : c, field4 : d) -> (a, b, c, d)){ opop: ($9205, $9206, $9207, $9208) -> $9202 $9209(x1x1: $9205,x2x2: $9206,x3x3: $9207,x4x4: $9208) } ) + +pub fun clause-tail-noop4std/core/hnd/clause-tail-noop4: forall<e,a,b,c,d,a1,b1,c1> (op : (c, d, a1, b1) -> e c1) -> clause1<(c, d, a1, b1),c1,b,e,a><ee: E,rr: V,hh: (E, V) -> V,a1a1: V,a2a2: V,a3a3: V,a4a4: V,bb: V>(opop: ($8433, $8434, $8435, $8436) -> $8430 $8437 : (a1a1: V,a2a2: V,a3a3: V,a4a4: V) -> ee: E bb: V)result: -> total clause1<(8491, 8492, 8493, 8494),8495,8490,8488,8489> : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<(std/core/types/tuple4: (V, V, V, V) -> Va1a1: V,a2a2: V,a3a3: V,a4a4: V),bb: V,hh: (E, V) -> V,ee: E,rr: V> + clause-tail-noop1std/core/hnd/clause-tail-noop1: (op : (($8433, $8434, $8435, $8436)) -> $8430 $8437) -> clause1<($8433, $8434, $8435, $8436),$8437,$8432,$8430,$8431>( fnfn: (($8433, $8434, $8435, $8436)) -> $8430 $8437((std/core/types/Tuple4: forall<a,b,c,d> (fst : a, snd : b, thd : c, field4 : d) -> (a, b, c, d)x1x1: $8433,x2x2: $8434,x3x3: $8435,x4x4: $8436)std/core/types/Tuple4: forall<a,b,c,d> (fst : a, snd : b, thd : c, field4 : d) -> (a, b, c, d)){ opop: ($8433, $8434, $8435, $8436) -> $8430 $8437(x1x1: $8433,x2x2: $8434,x3x3: $8435,x4x4: $8436) } ) + +pub fun clause-never4std/core/hnd/clause-never4: forall<a,b,c,d,a1,e,b1,c1> (op : (a, b, c, d) -> e c1) -> clause1<(a, b, c, d),a1,b1,e,c1>( opop: ($8257, $8258, $8259, $8260) -> $8262 $8264 : (a1a1: V,a2a2: V,a3a3: V,a4a4: V) -> ee: E rr: V )result: -> total clause1<(8315, 8316, 8317, 8318),8319,8321,8320,8322> : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<(std/core/types/tuple4: (V, V, V, V) -> Va1a1: V,a2a2: V,a3a3: V,a4a4: V),bb: V,hh: (E, V) -> V,ee: E,rr: V> + clause-never1std/core/hnd/clause-never1: (op : (($8257, $8258, $8259, $8260)) -> $8262 $8264) -> clause1<($8257, $8258, $8259, $8260),$8261,$8263,$8262,$8264>(fnfn: (($8257, $8258, $8259, $8260)) -> $8262 $8264((std/core/types/Tuple4: forall<a,b,c,d> (fst : a, snd : b, thd : c, field4 : d) -> (a, b, c, d)x1x1: $8257,x2x2: $8258,x3x3: $8259,x4x4: $8260)std/core/types/Tuple4: forall<a,b,c,d> (fst : a, snd : b, thd : c, field4 : d) -> (a, b, c, d)){ opop: ($8257, $8258, $8259, $8260) -> $8262 $8264(x1x1: $8257,x2x2: $8258,x3x3: $8259,x4x4: $8260) } ) + +pub fun @perform4( evev: ev<$6575> : evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>, opop: forall<e,a> ($6575<e,a>) -> clause1<($6569, $6570, $6571, $6572),$6573,$6575,e,a> : (forall<e1e1: E,rr: V> hh: (E, V) -> V<e1e1: E,rr: V> -> clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<(std/core/types/tuple4: (V, V, V, V) -> Va1a1: V,a2a2: V,a3a3: V,a4a4: V),bb: V,hh: (E, V) -> V,e1e1: E,rr: V>), x1x1: $6569 : a1a1: V, x2x2: $6570 : a2a2: V, x3x3: $6571 : a3a3: V, x4x4: $6572 : a4a4: V )result: -> 6648 6647 : ee: E bb: V + xperform1std/core/hnd/xperform1: (ev : ev<$6575>, op : forall<e,a> ($6575<e,a>) -> clause1<($6569, $6570, $6571, $6572),$6573,$6575,e,a>, x : ($6569, $6570, $6571, $6572)) -> $6574 $6573(evev: ev<$6575>,opop: forall<e,a> ($6575<e,a>) -> clause1<($6569, $6570, $6571, $6572),$6573,$6575,e,a>,(std/core/types/Tuple4: forall<a,b,c,d> (fst : a, snd : b, thd : c, field4 : d) -> (a, b, c, d)x1x1: $6569,x2x2: $6570,x3x3: $6571,x4x4: $6572)std/core/types/Tuple4: forall<a,b,c,d> (fst : a, snd : b, thd : c, field4 : d) -> (a, b, c, d)) + +fun under4std/core/hnd/under4: forall<a,b,c,d,a1,e,b1> (ev : ev<b1>, op : (a, b, c, d) -> e a1, x1 : a, x2 : b, x3 : c, x4 : d) -> e a1( evev: ev<$10080> : evstd/core/hnd/ev: ((E, V) -> V) -> V<hh: (E, V) -> V>, opop: ($10074, $10075, $10076, $10077) -> $10079 $10078 : (a1a1: V,a2a2: V,a3a3: V,a4a4: V) -> ee: E bb: V, x1x1: $10074 : a1a1: V, x2x2: $10075 : a2a2: V, x3x3: $10076 : a3a3: V, x4x4: $10077 : a4a4: V )result: -> 10167 10166 : ee: E bb: V + val w0w0: evv<_10088> = evv-swap-withstd/core/hnd/evv-swap-with: (ev : ev<$10080>) -> $10079 evv<_10088>(evev: ev<$10080>) + val zz: $10078 = opop: ($10074, $10075, $10076, $10077) -> $10079 $10078(x1x1: $10074,x2x2: $10075,x3x3: $10076,x4x4: $10077) + evv-setstd/core/hnd/evv-set: (w : evv<_10088>) -> $10079 ()(w0w0: evv<_10088>) + if yieldingstd/core/hnd/yielding: () -> $10079 bool() returnreturn: $10078 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $10079 $10078, a) -> $10079 $10078) -> $10079 $10078( fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($10119) -> $10079 $10078,resres: $10119) under1std/core/hnd/under1: (ev : ev<$10080>, op : ($10119) -> $10079 $10078, x : $10119) -> $10079 $10078(evev: ev<$10080>,contcont: ($10119) -> $10079 $10078,resres: $10119) )std/core/types/Unit: () + zz: $10078 + + +// ------------------------------------------- +// Open +// ------------------------------------------- + +pub fun @open-none0<bb: V,e1e1: E,e2e2: E>( ff: () -> $2709 $2708 : () -> e1e1: E bb: V )result: -> 2746 2744 : e2e2: E bb: V + val ww: evv<$2710> = evv-swap-create0std/core/hnd/evv-swap-create0: () -> $2710 evv<$2710>() + val xx: $2708 = cast-ev0std/core/hnd/cast-ev0: (f : () -> $2709 $2708) -> $2710 (() -> $2710 $2708)(ff: () -> $2709 $2708)() + val keepkeep: () = evv-setstd/core/hnd/evv-set: (w : evv<$2710>) -> $2710 ()(ww: evv<$2710>) + xx: $2708 + +pub fun @open-none1<aa: V,bb: V,e1e1: E,e2e2: E>( ff: ($2756) -> $2758 $2757 : aa: V -> e1e1: E bb: V, x1x1: $2756 : aa: V )result: -> 2802 2800 : e2e2: E bb: V + val ww: evv<$2759> = evv-swap-create0std/core/hnd/evv-swap-create0: () -> $2759 evv<$2759>() + val xx: $2757 = cast-ev1std/core/hnd/cast-ev1: (f : ($2756) -> $2758 $2757) -> $2759 (($2756) -> $2759 $2757)(ff: ($2756) -> $2758 $2757)(x1x1: $2756) + val keepkeep: () = evv-setstd/core/hnd/evv-set: (w : evv<$2759>) -> $2759 ()(ww: evv<$2759>) + xx: $2757 + +pub fun @open-none2<a1a1: V,a2a2: V,bb: V,e1e1: E,e2e2: E>( ff: ($2815, $2816) -> $2818 $2817 : (a1a1: V,a2a2: V) -> e1e1: E bb: V, x1x1: $2815 : a1a1: V, x2x2: $2816 : a2a2: V )result: -> 2869 2867 : e2e2: E bb: V + val ww: evv<$2819> = evv-swap-create0std/core/hnd/evv-swap-create0: () -> $2819 evv<$2819>() + val xx: $2817 = cast-ev2std/core/hnd/cast-ev2: (f : ($2815, $2816) -> $2818 $2817) -> $2819 (($2815, $2816) -> $2819 $2817)(ff: ($2815, $2816) -> $2818 $2817)(x1x1: $2815,x2x2: $2816) + val keepkeep: () = evv-setstd/core/hnd/evv-set: (w : evv<$2819>) -> $2819 ()(ww: evv<$2819>) + xx: $2817 + +pub fun @open-none3<a1a1: V,a2a2: V,a3a3: V,bb: V,e1e1: E,e2e2: E>( ff: ($2885, $2886, $2887) -> $2889 $2888 : (a1a1: V,a2a2: V,a3a3: V) -> e1e1: E bb: V, x1x1: $2885 : a1a1: V, x2x2: $2886 : a2a2: V, x3x3: $2887 : a3a3: V )result: -> 2947 2945 : e2e2: E bb: V + val ww: evv<$2890> = evv-swap-create0std/core/hnd/evv-swap-create0: () -> $2890 evv<$2890>() + val xx: $2888 = cast-ev3std/core/hnd/cast-ev3: (f : ($2885, $2886, $2887) -> $2889 $2888) -> $2890 (($2885, $2886, $2887) -> $2890 $2888)(ff: ($2885, $2886, $2887) -> $2889 $2888)(x1x1: $2885,x2x2: $2886,x3x3: $2887) + val keepkeep: () = evv-setstd/core/hnd/evv-set: (w : evv<$2890>) -> $2890 ()(ww: evv<$2890>) + xx: $2888 + +pub fun @open-none4<a1a1: V,a2a2: V,a3a3: V,a4a4: V,bb: V,e1e1: E,e2e2: E>( ff: ($2966, $2967, $2968, $2969) -> $2971 $2970 : (a1a1: V,a2a2: V,a3a3: V,a4a4: V) -> e1e1: E bb: V, x1x1: $2966 : a1a1: V, x2x2: $2967 : a2a2: V, x3x3: $2968 : a3a3: V, x4x4: $2969 : a4a4: V )result: -> 3036 3034 : e2e2: E bb: V + val ww: evv<$2972> = evv-swap-create0std/core/hnd/evv-swap-create0: () -> $2972 evv<$2972>() + val xx: $2970 = cast-ev4std/core/hnd/cast-ev4: (f : ($2966, $2967, $2968, $2969) -> $2971 $2970) -> $2972 (($2966, $2967, $2968, $2969) -> $2972 $2970)(ff: ($2966, $2967, $2968, $2969) -> $2971 $2970)(x1x1: $2966,x2x2: $2967,x3x3: $2968,x4x4: $2969) + val keepkeep: () = evv-setstd/core/hnd/evv-set: (w : evv<$2972>) -> $2972 ()(ww: evv<$2972>) + xx: $2970 + + +noinline fun open-at1std/core/hnd/open-at1: forall<a,b,e,e1> (i : ev-index, f : (a) -> e b, x : a) -> e1 b<aa: V,bb: V,e1e1: E,e2e2: E>( ii: ev-index: ev-indexstd/core/hnd/ev-index: V, ff: ($5130) -> $5132 $5131 : aa: V -> e1e1: E bb: V, xx: $5130 : aa: V )result: -> 5225 5223 : e2e2: E bb: V + val ww: evv<$5133> = evv-swap-create1std/core/hnd/evv-swap-create1: (i : ev-index) -> $5133 evv<$5133>(ii: ev-index) + val yy: $5131 = cast-ev1std/core/hnd/cast-ev1: (f : ($5130) -> $5132 $5131) -> $5133 (($5130) -> $5133 $5131)(ff: ($5130) -> $5132 $5131)(xx: $5130) + evv-setstd/core/hnd/evv-set: (w : evv<$5133>) -> $5133 ()(ww: evv<$5133>) + if yieldingstd/core/hnd/yielding: () -> $5133 bool() returnreturn: $5131 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $5133 $5131, a) -> $5133 $5131) -> $5133 $5131(fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($5179) -> $5133 $5131,resres: $5179){ open-at1std/core/hnd/open-at1: (i : ev-index, f : ($5179) -> $5133 $5131, x : $5179) -> $5133 $5131(pretend-decreasingstd/core/undiv/pretend-decreasing: (x : ev-index) -> $5133 ev-index(ii: ev-index),contcont: ($5179) -> $5133 $5131,resres: $5179) })std/core/types/Unit: () + yy: $5131 + +pub fun @open-at0<bb: V,e1e1: E,e2e2: E>( ii: ev-index: ev-indexstd/core/hnd/ev-index: V, ff: () -> $5239 $5238 : () -> e1e1: E bb: V )result: -> 5319 5317 : e2e2: E bb: V + val ww: evv<$5240> = evv-swap-create1std/core/hnd/evv-swap-create1: (i : ev-index) -> $5240 evv<$5240>(ii: ev-index) + val yy: $5238 = cast-ev0std/core/hnd/cast-ev0: (f : () -> $5239 $5238) -> $5240 (() -> $5240 $5238)(ff: () -> $5239 $5238)() + evv-setstd/core/hnd/evv-set: (w : evv<$5240>) -> $5240 ()(ww: evv<$5240>) + if yieldingstd/core/hnd/yielding: () -> $5240 bool() returnreturn: $5238 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $5240 $5238, a) -> $5240 $5238) -> $5240 $5238(fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($5282) -> $5240 $5238,resres: $5282){ open-at1std/core/hnd/open-at1: (i : ev-index, f : ($5282) -> $5240 $5238, x : $5282) -> $5240 $5238(ii: ev-index,contcont: ($5282) -> $5240 $5238,resres: $5282) })std/core/types/Unit: () + yy: $5238 + +pub fun @open-at1<aa: V,bb: V,e1e1: E,e2e2: E>( ii: ev-index: ev-indexstd/core/hnd/ev-index: V, ff: ($5329) -> $5331 $5330 : aa: V -> e1e1: E bb: V, xx: $5329 : aa: V )result: -> 5418 5416 : e2e2: E bb: V + val ww: evv<$5332> = evv-swap-create1std/core/hnd/evv-swap-create1: (i : ev-index) -> $5332 evv<$5332>(ii: ev-index) + val yy: $5330 = cast-ev1std/core/hnd/cast-ev1: (f : ($5329) -> $5331 $5330) -> $5332 (($5329) -> $5332 $5330)(ff: ($5329) -> $5331 $5330)(xx: $5329) + evv-setstd/core/hnd/evv-set: (w : evv<$5332>) -> $5332 ()(ww: evv<$5332>) + if yieldingstd/core/hnd/yielding: () -> $5332 bool() returnreturn: $5330 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $5332 $5330, a) -> $5332 $5330) -> $5332 $5330(fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($5378) -> $5332 $5330,resres: $5378){ open-at1std/core/hnd/open-at1: (i : ev-index, f : ($5378) -> $5332 $5330, x : $5378) -> $5332 $5330(ii: ev-index,contcont: ($5378) -> $5332 $5330,resres: $5378) })std/core/types/Unit: () + yy: $5330 + +pub fun @open-at2<a1a1: V,a2a2: V,bb: V,e1e1: E,e2e2: E> ( ii: ev-index: ev-indexstd/core/hnd/ev-index: V, ff: ($5431, $5432) -> $5434 $5433 : (a1a1: V,a2a2: V) -> e1e1: E bb: V, x1x1: $5431 : a1a1: V, x2x2: $5432 : a2a2: V )result: -> 5528 5526 : e2e2: E bb: V + val ww: evv<$5435> = evv-swap-create1std/core/hnd/evv-swap-create1: (i : ev-index) -> $5435 evv<$5435>(ii: ev-index) + val yy: $5433 = cast-ev2std/core/hnd/cast-ev2: (f : ($5431, $5432) -> $5434 $5433) -> $5435 (($5431, $5432) -> $5435 $5433)(ff: ($5431, $5432) -> $5434 $5433)(x1x1: $5431,x2x2: $5432) + evv-setstd/core/hnd/evv-set: (w : evv<$5435>) -> $5435 ()(ww: evv<$5435>) + if yieldingstd/core/hnd/yielding: () -> $5435 bool() returnreturn: $5433 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $5435 $5433, a) -> $5435 $5433) -> $5435 $5433(fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($5485) -> $5435 $5433,resres: $5485){ open-at1std/core/hnd/open-at1: (i : ev-index, f : ($5485) -> $5435 $5433, x : $5485) -> $5435 $5433(ii: ev-index,contcont: ($5485) -> $5435 $5433,resres: $5485) })std/core/types/Unit: () + yy: $5433 + +pub fun @open-at3<a1a1: V,a2a2: V,a3a3: V,bb: V,e1e1: E,e2e2: E> ( ii: ev-index: ev-indexstd/core/hnd/ev-index: V, ff: ($5544, $5545, $5546) -> $5548 $5547 : (a1a1: V,a2a2: V,a3a3: V) -> e1e1: E bb: V, x1x1: $5544 : a1a1: V, x2x2: $5545 : a2a2: V, x3x3: $5546 : a3a3: V )result: -> 5649 5647 : e2e2: E bb: V + val ww: evv<$5549> = evv-swap-create1std/core/hnd/evv-swap-create1: (i : ev-index) -> $5549 evv<$5549>(ii: ev-index) + val yy: $5547 = cast-ev3std/core/hnd/cast-ev3: (f : ($5544, $5545, $5546) -> $5548 $5547) -> $5549 (($5544, $5545, $5546) -> $5549 $5547)(ff: ($5544, $5545, $5546) -> $5548 $5547)(x1x1: $5544,x2x2: $5545,x3x3: $5546) + evv-setstd/core/hnd/evv-set: (w : evv<$5549>) -> $5549 ()(ww: evv<$5549>) + if yieldingstd/core/hnd/yielding: () -> $5549 bool() returnreturn: $5547 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $5549 $5547, a) -> $5549 $5547) -> $5549 $5547(fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($5603) -> $5549 $5547,resres: $5603){ open-at1std/core/hnd/open-at1: (i : ev-index, f : ($5603) -> $5549 $5547, x : $5603) -> $5549 $5547(ii: ev-index,contcont: ($5603) -> $5549 $5547,resres: $5603) })std/core/types/Unit: () + yy: $5547 + +pub fun @open-at4<a1a1: V,a2a2: V,a3a3: V,a4a4: V,bb: V,e1e1: E,e2e2: E> ( ii: ev-index: ev-indexstd/core/hnd/ev-index: V, ff: ($5668, $5669, $5670, $5671) -> $5673 $5672 : (a1a1: V,a2a2: V,a3a3: V,a4a4: V) -> e1e1: E bb: V, x1x1: $5668 : a1a1: V, x2x2: $5669 : a2a2: V, x3x3: $5670 : a3a3: V, x4x4: $5671 : a4a4: V )result: -> 5781 5779 : e2e2: E bb: V + val ww: evv<$5674> = evv-swap-create1std/core/hnd/evv-swap-create1: (i : ev-index) -> $5674 evv<$5674>(ii: ev-index) + val yy: $5672 = cast-ev4std/core/hnd/cast-ev4: (f : ($5668, $5669, $5670, $5671) -> $5673 $5672) -> $5674 (($5668, $5669, $5670, $5671) -> $5674 $5672)(ff: ($5668, $5669, $5670, $5671) -> $5673 $5672)(x1x1: $5668,x2x2: $5669,x3x3: $5670,x4x4: $5671) + evv-setstd/core/hnd/evv-set: (w : evv<$5674>) -> $5674 ()(ww: evv<$5674>) + if yieldingstd/core/hnd/yielding: () -> $5674 bool() returnreturn: $5672 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $5674 $5672, a) -> $5674 $5672) -> $5674 $5672(fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($5732) -> $5674 $5672,resres: $5732){ open-at1std/core/hnd/open-at1: (i : ev-index, f : ($5732) -> $5674 $5672, x : $5732) -> $5674 $5672(ii: ev-index,contcont: ($5732) -> $5674 $5672,resres: $5732) })std/core/types/Unit: () + yy: $5672 + + +noinline fun open1std/core/hnd/open1: forall<a,b,e,e1> (indices : vector<ev-index>, f : (a) -> e b, x : a) -> e1 b<aa: V,bb: V,e1e1: E,e2e2: E>( indicesindices: vector<ev-index> : vectorstd/core/types/vector: V -> V<ev-indexstd/core/hnd/ev-index: V>, ff: ($5803) -> $5805 $5804 : aa: V -> e1e1: E bb: V, xx: $5803 : aa: V )result: -> 5898 5896 : e2e2: E bb: V + val ww: evv<$5806> = evv-swap-createstd/core/hnd/evv-swap-create: (indices : vector<ev-index>) -> $5806 evv<$5806>(indicesindices: vector<ev-index>) + val yy: $5804 = cast-ev1std/core/hnd/cast-ev1: (f : ($5803) -> $5805 $5804) -> $5806 (($5803) -> $5806 $5804)(ff: ($5803) -> $5805 $5804)(xx: $5803) + evv-setstd/core/hnd/evv-set: (w : evv<$5806>) -> $5806 ()(ww: evv<$5806>) + if yieldingstd/core/hnd/yielding: () -> $5806 bool() returnreturn: $5804 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $5806 $5804, a) -> $5806 $5804) -> $5806 $5804(fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($5852) -> $5806 $5804,resres: $5852){ open1std/core/hnd/open1: (indices : vector<ev-index>, f : ($5852) -> $5806 $5804, x : $5852) -> $5806 $5804(pretend-decreasingstd/core/undiv/pretend-decreasing: (x : vector<ev-index>) -> $5806 vector<ev-index>(indicesindices: vector<ev-index>),contcont: ($5852) -> $5806 $5804,resres: $5852) })std/core/types/Unit: () + yy: $5804 + + +pub fun @open0<bb: V,e1e1: E,e2e2: E>( indicesindices: vector<ev-index> : vectorstd/core/types/vector: V -> V<ev-indexstd/core/hnd/ev-index: V>, ff: () -> $5912 $5911 : () -> e1e1: E bb: V )result: -> 5992 5990 : e2e2: E bb: V + val ww: evv<$5913> = evv-swap-createstd/core/hnd/evv-swap-create: (indices : vector<ev-index>) -> $5913 evv<$5913>(indicesindices: vector<ev-index>) + val yy: $5911 = cast-ev0std/core/hnd/cast-ev0: (f : () -> $5912 $5911) -> $5913 (() -> $5913 $5911)(ff: () -> $5912 $5911)() + evv-setstd/core/hnd/evv-set: (w : evv<$5913>) -> $5913 ()(ww: evv<$5913>) + if yieldingstd/core/hnd/yielding: () -> $5913 bool() returnreturn: $5911 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $5913 $5911, a) -> $5913 $5911) -> $5913 $5911(fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($5955) -> $5913 $5911,resres: $5955){ open1std/core/hnd/open1: (indices : vector<ev-index>, f : ($5955) -> $5913 $5911, x : $5955) -> $5913 $5911(indicesindices: vector<ev-index>,contcont: ($5955) -> $5913 $5911,resres: $5955) })std/core/types/Unit: () + yy: $5911 + +pub fun @open1<aa: V,bb: V,e1e1: E,e2e2: E>( indicesindices: vector<ev-index> : vectorstd/core/types/vector: V -> V<ev-indexstd/core/hnd/ev-index: V>, ff: ($6002) -> $6004 $6003 : aa: V -> e1e1: E bb: V, xx: $6002 : aa: V )result: -> 6091 6089 : e2e2: E bb: V + val ww: evv<$6005> = evv-swap-createstd/core/hnd/evv-swap-create: (indices : vector<ev-index>) -> $6005 evv<$6005>(indicesindices: vector<ev-index>) + val yy: $6003 = cast-ev1std/core/hnd/cast-ev1: (f : ($6002) -> $6004 $6003) -> $6005 (($6002) -> $6005 $6003)(ff: ($6002) -> $6004 $6003)(xx: $6002) + evv-setstd/core/hnd/evv-set: (w : evv<$6005>) -> $6005 ()(ww: evv<$6005>) + if yieldingstd/core/hnd/yielding: () -> $6005 bool() returnreturn: $6003 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $6005 $6003, a) -> $6005 $6003) -> $6005 $6003(fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($6051) -> $6005 $6003,resres: $6051){ open1std/core/hnd/open1: (indices : vector<ev-index>, f : ($6051) -> $6005 $6003, x : $6051) -> $6005 $6003(indicesindices: vector<ev-index>,contcont: ($6051) -> $6005 $6003,resres: $6051) })std/core/types/Unit: () + yy: $6003 + +pub fun @open2<a1a1: V,a2a2: V,bb: V,e1e1: E,e2e2: E>( indicesindices: vector<ev-index> : vectorstd/core/types/vector: V -> V<ev-indexstd/core/hnd/ev-index: V>, ff: ($6104, $6105) -> $6107 $6106 : (a1a1: V,a2a2: V) -> e1e1: E bb: V, x1x1: $6104 : a1a1: V, x2x2: $6105 : a2a2: V )result: -> 6201 6199 : e2e2: E bb: V + val ww: evv<$6108> = evv-swap-createstd/core/hnd/evv-swap-create: (indices : vector<ev-index>) -> $6108 evv<$6108>(indicesindices: vector<ev-index>) + val yy: $6106 = cast-ev2std/core/hnd/cast-ev2: (f : ($6104, $6105) -> $6107 $6106) -> $6108 (($6104, $6105) -> $6108 $6106)(ff: ($6104, $6105) -> $6107 $6106)(x1x1: $6104,x2x2: $6105) + evv-setstd/core/hnd/evv-set: (w : evv<$6108>) -> $6108 ()(ww: evv<$6108>) + if yieldingstd/core/hnd/yielding: () -> $6108 bool() returnreturn: $6106 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $6108 $6106, a) -> $6108 $6106) -> $6108 $6106(fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($6158) -> $6108 $6106,resres: $6158){ open1std/core/hnd/open1: (indices : vector<ev-index>, f : ($6158) -> $6108 $6106, x : $6158) -> $6108 $6106(indicesindices: vector<ev-index>,contcont: ($6158) -> $6108 $6106,resres: $6158) })std/core/types/Unit: () + yy: $6106 + +pub fun @open3<a1a1: V,a2a2: V,a3a3: V,bb: V,e1e1: E,e2e2: E>( indicesindices: vector<ev-index> : vectorstd/core/types/vector: V -> V<ev-indexstd/core/hnd/ev-index: V>, ff: ($6217, $6218, $6219) -> $6221 $6220 : (a1a1: V,a2a2: V,a3a3: V) -> e1e1: E bb: V, x1x1: $6217 : a1a1: V, x2x2: $6218 : a2a2: V, x3x3: $6219 : a3a3: V )result: -> 6322 6320 : e2e2: E bb: V + val ww: evv<$6222> = evv-swap-createstd/core/hnd/evv-swap-create: (indices : vector<ev-index>) -> $6222 evv<$6222>(indicesindices: vector<ev-index>) + val yy: $6220 = cast-ev3std/core/hnd/cast-ev3: (f : ($6217, $6218, $6219) -> $6221 $6220) -> $6222 (($6217, $6218, $6219) -> $6222 $6220)(ff: ($6217, $6218, $6219) -> $6221 $6220)(x1x1: $6217,x2x2: $6218,x3x3: $6219) + evv-setstd/core/hnd/evv-set: (w : evv<$6222>) -> $6222 ()(ww: evv<$6222>) + if yieldingstd/core/hnd/yielding: () -> $6222 bool() returnreturn: $6220 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $6222 $6220, a) -> $6222 $6220) -> $6222 $6220(fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($6276) -> $6222 $6220,resres: $6276){ open1std/core/hnd/open1: (indices : vector<ev-index>, f : ($6276) -> $6222 $6220, x : $6276) -> $6222 $6220(indicesindices: vector<ev-index>,contcont: ($6276) -> $6222 $6220,resres: $6276) })std/core/types/Unit: () + yy: $6220 + +pub fun @open4<a1a1: V,a2a2: V,a3a3: V,a4a4: V,bb: V,e1e1: E,e2e2: E>( indicesindices: vector<ev-index> : vectorstd/core/types/vector: V -> V<ev-indexstd/core/hnd/ev-index: V>, ff: ($6341, $6342, $6343, $6344) -> $6346 $6345 : (a1a1: V,a2a2: V,a3a3: V,a4a4: V) -> e1e1: E bb: V, x1x1: $6341 : a1a1: V, x2x2: $6342 : a2a2: V, x3x3: $6343 : a3a3: V, x4x4: $6344 : a4a4: V )result: -> 6454 6452 : e2e2: E bb: V + val ww: evv<$6347> = evv-swap-createstd/core/hnd/evv-swap-create: (indices : vector<ev-index>) -> $6347 evv<$6347>(indicesindices: vector<ev-index>) + val yy: $6345 = cast-ev4std/core/hnd/cast-ev4: (f : ($6341, $6342, $6343, $6344) -> $6346 $6345) -> $6347 (($6341, $6342, $6343, $6344) -> $6347 $6345)(ff: ($6341, $6342, $6343, $6344) -> $6346 $6345)(x1x1: $6341,x2x2: $6342,x3x3: $6343,x4x4: $6344) + evv-setstd/core/hnd/evv-set: (w : evv<$6347>) -> $6347 ()(ww: evv<$6347>) + if yieldingstd/core/hnd/yielding: () -> $6347 bool() returnreturn: $6345 yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $6347 $6345, a) -> $6347 $6345) -> $6347 $6345(fnfn: forall<a,b,e> (cont : (a) -> e b, res : a) -> e b(contcont: ($6405) -> $6347 $6345,resres: $6405){ open1std/core/hnd/open1: (indices : vector<ev-index>, f : ($6405) -> $6347 $6345, x : $6405) -> $6347 $6345(indicesindices: vector<ev-index>,contcont: ($6405) -> $6347 $6345,resres: $6405) })std/core/types/Unit: () + yy: $6345 + +// ------------------------------------------- +// capture yields +// ------------------------------------------- + +pub fun unsafe-try-finalizestd/core/hnd/unsafe-try-finalize: forall<a,e> (action : () -> e a) -> e either<yield-info,a>( actionaction: () -> $10191 $10190 : () -> ee: E aa: V )result: -> 10206 either<yield-info,10205> : ee: E eitherstd/core/types/either: (V, V) -> V<yield-infostd/core/hnd/yield-info: V,aa: V> + try-finalize-promptstd/core/hnd/try-finalize-prompt: (res : $10190) -> $10191 either<yield-info,$10190>(actionaction: () -> $10191 $10190()); + +fun try-finalize-promptstd/core/hnd/try-finalize-prompt: forall<a,e> (res : a) -> e either<yield-info,a>( resres: $9870 : aa: V )result: -> 9959 either<yield-info,9958> : ee: E eitherstd/core/types/either: (V, V) -> V<yield-infostd/core/hnd/yield-info: V,aa: V> + if yielding-non-finalstd/core/hnd/yielding-non-final: () -> $9871 bool() returnreturn: either<yield-info,$9870> yield-contstd/core/hnd/yield-cont: (f : forall<a> ((a) -> $9871 $9870, a) -> $9871 either<yield-info,$9870>) -> $9871 either<yield-info,$9870>(fnfn: forall<a,b,e> (cont : (a) -> e b, x : a) -> e either<yield-info,b>(contcont: ($9887) -> $9871 $9870,xx: $9887) try-finalize-promptstd/core/hnd/try-finalize-prompt: (res : $9870) -> $9871 either<yield-info,$9870>(pretend-decreasingstd/core/undiv/pretend-decreasing: (x : $9870) -> $9871 $9870(contcont: ($9887) -> $9871 $9870(xx: $9887))) )std/core/types/Unit: () + if !std/core/types/bool/(!): (b : bool) -> $9871 boolyieldingstd/core/hnd/yielding: () -> $9871 bool() then Rightstd/core/types/Right: forall<a,b> (right : b) -> either<a,b>(resres: $9870) else Leftstd/core/types/Left: forall<a,b> (left : a) -> either<a,b>(yield-capturestd/core/hnd/yield-capture: () -> $9871 yield-info()) +
diff --git a/doc/std_core_hnd.html b/doc/std_core_hnd.html index eef4015e1..a754dcca2 100644 --- a/doc/std_core_hnd.html +++ b/doc/std_core_hnd.html @@ -15,7 +15,7 @@ -

std/core/hnd▲toc

+

std/core/hnd▲toc

- -
fun clause-control1( clause : (x : a, k : (b) -> e d) -> e d ) : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<a,b,c,e,d>
+ +
fun clause-control1( clause : (x : a, k : (b) -> e d) -> e d ) : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<a,b,c,e,d>

Generic control clause.

fun clause-control3( op : (x1 : a, x2 : b, x3 : c, k : (d) -> e b1) -> e b1 ) : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<(a, b, c),d,a1,e,b1>
fun clause-control4( op : (x1 : a, x2 : b, x3 : c, x4 : d, k : (a1) -> e c1) -> e c1 ) : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<(a, b, c, d),a1,b1,e,c1>
@@ -162,38 +162,38 @@

Internal effect handler primitives.

Tail-resumptive clause: resumes exactly once at the end (these can be executed ‘in-place’ without capturing a resumption).

fun clause-tail3( op : (c, d, a1) -> e b1 ) : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<(c, d, a1),b1,b,e,a>
fun clause-tail4( op : (c, d, a1, b1) -> e c1 ) : clause1std/core/hnd/clause1: (V, V, (E, V) -> V, E, V) -> V<(c, d, a1, b1),c1,b,e,a>
- -
+ +

Effect handler evidence of a handler h in the context.

-
-
+

Index into an evidence vector.

-
+

The tag of a handler identifies the type at runtime (e.g. "exn/core/std"). -

- - + +
fun finally( fin : () -> e (), action : () -> e a ) : e a
-
fun initially( init : (intstd/core/types/int: V) -> e (), action : () -> e a ) : e a
- - +
fun initially( init : (intstd/core/types/int: V) -> e (), action : () -> e a ) : e a
+ +
fun yield-bind( x : a, next : (a) -> e b ) : e b
fun yield-bind2( x : a, extend : (a) -> e b, next : (a) -> e b ) : e b
fun yield-extend( next : (a) -> e b ) : e b
- - - + + + diff --git a/doc/std_core_int-source.html b/doc/std_core_int-source.html index 4b9698179..8137534d3 100644 --- a/doc/std_core_int-source.html +++ b/doc/std_core_int-source.html @@ -10,11 +10,377 @@ - documentation +int.kk documentation -

+
/*---------------------------------------------------------------------------
+  Copyright 2012-2024, Microsoft Research, Daan Leijen.
+
+  This is free software; you can redistribute it and/or modify it under the
+  terms of the Apache License, Version 2.0. A copy of the License can be
+  found in the LICENSE file at the root of this distribution.
+---------------------------------------------------------------------------*/
+
+// Standard integer `:int` functions.
+//
+// These are arbitrary precision signed integer with an efficient runtime representation.
+// For more details, see:
+//
+// >   "What About the Integer Numbers?
+// >   "Fast Arithmetic with Tagged Integers -- A Plea for Hardware Support"
+// >   Daan Leijen, Technical report MSR-TR-2022-17, 2022-07-11, v1.0. Presented at the ML workshop 2022."
+// >   <https://www.microsoft.com/en-us/research/uploads/prod/2022/07/int.pdf>
+//
+module std/core/intstd/core/int
+
+import std/core/typesstd/core/types
+
+extern import
+  c  file "inline/int.h"
+  js file "inline/int.js"
+
+pub fip fun orderstd/core/int/order: (i : int) -> order( ii: int : intstd/core/types/int: V )result: -> total order : orderstd/core/types/order: V
+  if ii: int <std/core/int/(<): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
then Ltstd/core/types/Lt: order + elif ii: int >std/core/int/(>): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
then Gtstd/core/types/Gt: order + else Eqstd/core/types/Eq: order
+ +// Compare two integers +pub inline fip fun cmpstd/core/int/cmp: (x : int, y : int) -> order(^xx: int : intstd/core/types/int: V, ^yy: int : intstd/core/types/int: V)result: -> total order : orderstd/core/types/order: V + if (xx: int==std/core/int/(==): (x : int, y : int) -> boolyy: int) then Eqstd/core/types/Eq: order elif (xx: int>std/core/int/(>): (x : int, y : int) -> boolyy: int) then Gtstd/core/types/Gt: order else Ltstd/core/types/Lt: order + // c inline "kk_int_as_order(kk_integer_cmp_borrow(#1,#2,kk_context()),kk_context())" + // cs "Primitive.IntCompare" + // js "$std_core_types._int_compare" + +// Order two integers in ascending order. +pub inline fip fun order2std/core/int/order2: (x : int, y : int) -> order2<int>(xx: int : intstd/core/types/int: V, yy: int : intstd/core/types/int: V)result: -> total order2<int> : order2std/core/types/order2: V -> V<intstd/core/types/int: V> + if (xx: int==std/core/int/(==): (x : int, y : int) -> boolyy: int) then Eq2std/core/types/Eq2: forall<a> (eq : a) -> order2<a>(xx: int) elif (xx: int <std/core/int/(<): (x : int, y : int) -> bool yy: int) then Lt2std/core/types/Lt2: forall<a> (lt : a, gt : a) -> order2<a>(xx: int,yy: int) else Gt2std/core/types/Gt2: forall<a> (lt : a, gt : a) -> order2<a>(yy: int,xx: int) + +// Are two integers equal? +pub inline fip extern (==)std/core/int/(==): (x : int, y : int) -> bool(^x : intstd/core/types/int: V, ^y : intstd/core/types/int: V) : boolstd/core/types/bool: V + c "kk_integer_eq_borrow" + cs inline "(#1 == #2)" + js "$std_core_types._int_eq" + +// Are two integers not equal? +pub inline fip extern (!=)std/core/int/(!=): (x : int, y : int) -> bool(^x : intstd/core/types/int: V, ^y : intstd/core/types/int: V) : boolstd/core/types/bool: V + c "kk_integer_neq_borrow" + cs inline "(#1 != #2)" + js "$std_core_types._int_ne" + +// Is the first integer smaller or equal to the second? +pub inline fip extern (<=)std/core/int/(<=): (x : int, y : int) -> bool(^x : intstd/core/types/int: V, ^y : intstd/core/types/int: V) : boolstd/core/types/bool: V + c "kk_integer_lte_borrow" + cs inline "(#1 <= #2)" + js "$std_core_types._int_le" + +// Is the first integer greater or equal to the second? +pub inline fip extern (>=)std/core/int/(>=): (x : int, y : int) -> bool(^x : intstd/core/types/int: V, ^y : intstd/core/types/int: V) : boolstd/core/types/bool: V + c "kk_integer_gte_borrow" + cs inline "(#1 >= #2)" + js "$std_core_types._int_ge" + +// Is the first integer smaller than the second? +pub inline fip extern (<)std/core/int/(<): (x : int, y : int) -> bool(^x : intstd/core/types/int: V, ^y : intstd/core/types/int: V) : boolstd/core/types/bool: V + c "kk_integer_lt_borrow" + cs inline "(#1 < #2)" + js "$std_core_types._int_lt" + +// Is the first integer greater than the second? +pub inline fip extern (>)std/core/int/(>): (x : int, y : int) -> bool(^x : intstd/core/types/int: V, ^y : intstd/core/types/int: V) : boolstd/core/types/bool: V + c "kk_integer_gt_borrow" + cs inline "(#1 > #2)" + js "$std_core_types._int_gt" + +inline fip extern int-addstd/core/int/int-add: (int, int) -> int : (intstd/core/types/int: V,intstd/core/types/int: V) -> intstd/core/types/int: V + c "kk_integer_add" + cs inline "(#1 + #2)" + js "$std_core_types._int_add" + +// Add two integers. +pub fip fun (+)std/core/int/(+): (x : int, y : int) -> int(xx: int : intstd/core/types/int: V, yy: int : intstd/core/types/int: V )result: -> total int : intstd/core/types/int: V + int-addstd/core/int/int-add: (int, int) -> int(xx: int,yy: int) + +inline fip extern int-substd/core/int/int-sub: (int, int) -> int : (intstd/core/types/int: V,intstd/core/types/int: V) -> intstd/core/types/int: V + c "kk_integer_sub" + cs inline "(#1 - #2)" + js "$std_core_types._int_sub" + +// Substract two integers. +pub fip fun (-)std/core/int/(-): (x : int, y : int) -> int(xx: int : intstd/core/types/int: V, yy: int : intstd/core/types/int: V )result: -> total int : intstd/core/types/int: V + int-substd/core/int/int-sub: (int, int) -> int(xx: int,yy: int) + +// Multiply two integers. +pub inline fip extern (*)std/core/int/(*): (int, int) -> int : (intstd/core/types/int: V,intstd/core/types/int: V) -> intstd/core/types/int: V + c "kk_integer_mul" + cs inline "(#1 * #2)" + js "$std_core_types._int_mul" + +// Euclidean-0 division of two integers. See also `divmod:(x : int, y : int) -> (int,int)`. +pub inline fip extern (/)std/core/int/(/): (x : int, y : int) -> int(x:intstd/core/types/int: V,y:intstd/core/types/int: V) : intstd/core/types/int: V + c "kk_integer_div" + cs "Primitive.IntDiv" + js "$std_core_types._int_div" + +// Euclidean modulus of two integers; always a non-negative number. See also `divmod:(x : int, y : int) -> (int,int)`. +pub inline fip extern (%)std/core/int/(%): (int, int) -> int : (intstd/core/types/int: V,intstd/core/types/int: V) -> intstd/core/types/int: V + c "kk_integer_mod" + cs "Primitive.IntMod" + js "$std_core_types._int_mod" + +/* Euclidean-0 division & modulus. +Euclidean division is defined as: For any `D` and `d` where ``d!=0`` , we have: + +1. ``D == d*(D/d) + (D%d)`` +2. ``D%d`` is always positive where ``0 <= D%d < abs(d)`` + +Moreover, Euclidean-0 is a total function, for the case where `d==0` we have +that ``D%0 == D`` and ``D/0 == 0`` . So property (1) still holds, but not property (2). + +Useful laws that hold for Euclidean-0 division: + +* ``D/(-d) == -(D/d)`` +* ``D%(-d) == D%d`` +* ``D/(2^n) == sar(D,n) `` (where ``2^n`` means ``2`` to the power of ``n``) +* ``D%(2^n) == D & ((2^n) - 1) `` + +See also _Division and modulus for computer scientists, Daan Leijen, 2001_ for further information +(available at: <https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf>). +*/ +pub fip extern divmodstd/core/int/divmod: (x : int, y : int) -> (int, int)(xx: int:intstd/core/types/int: V,yy: int:intstd/core/types/int: V) : (std/core/types/tuple2: (V, V) -> Vintstd/core/types/int: V,intstd/core/types/int: V) + c "kk_integer_div_mod_tuple" + cs "Primitive.IntDivMod" + js "$std_core_types._int_divmod" + +pub fip fun negatestd/core/int/negate: (i : int) -> int(ii: int : intstd/core/types/int: V)result: -> total int : intstd/core/types/int: V + ~std/core/int/(~): (i : int) -> intii: int + +// Negate an integer. +pub inline fip extern (~)std/core/int/(~): (i : int) -> int(i:intstd/core/types/int: V) : intstd/core/types/int: V + c "kk_integer_neg" + cs inline "(-#1)" + js "$std_core_types._int_negate" + +// Is this an odd integer? +pub inline fip extern is-oddstd/core/int/is-odd: (i : int) -> bool( i : intstd/core/types/int: V ) : boolstd/core/types/bool: V + c "kk_integer_is_odd" + cs inline "!(#1.IsEven)" + js "$std_core_types._int_isodd" + +// Is this equal to zero? +pub inline fip extern is-zerostd/core/int/is-zero: (x : int) -> bool( ^x : intstd/core/types/int: V) : boolstd/core/types/bool: V + c inline "kk_integer_is_zero_borrow(#1)" + cs inline "(#1.IsZero)" + js "$std_core_types._int_iszero" + +// Return the absolute value of an integer. +pub inline fip extern absstd/core/int/abs: (i : int) -> int(i : intstd/core/types/int: V) : intstd/core/types/int: V + c "kk_integer_abs" + cs "BigInteger.Abs" + js "$std_core_types._int_abs" + + + +// Increment +pub fip fun incstd/core/int/inc: (i : int) -> int( ii: int : intstd/core/types/int: V )result: -> total int : intstd/core/types/int: V + ii: int +std/core/int/(+): (x : int, y : int) -> int 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
+ +// Decrement +pub fip fun decstd/core/int/dec: (i : int) -> int( ii: int : intstd/core/types/int: V )result: -> total int : intstd/core/types/int: V + ii: int -std/core/int/(-): (x : int, y : int) -> int 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
+ +// Calculate ``10^exp`` +pub fip fun exp10std/core/int/exp10: (exp : int) -> int( expexp: int : intstd/core/types/int: V )result: -> total int : intstd/core/types/int: V + 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
.mul-exp10std/core/int/mul-exp10: (i : int, n : int) -> int(expexp: int
) + +// Raise an integer `i` to the power of `exp`. +pub fip extern powstd/core/int/pow: (i : int, exp : int) -> int( ii: int : intstd/core/types/int: V, expexp: int : intstd/core/types/int: V ) : intstd/core/types/int: V + c "kk_integer_pow" + cs "Primitive.IntPow" + js "$std_core_types._int_pow" + +// Raise an integer `i` to the power of `exp`. +pub fip fun (^)std/core/int/(^): (i : int, exp : int) -> int(ii: int : intstd/core/types/int: V, expexp: int : intstd/core/types/int: V )result: -> total int : intstd/core/types/int: V + powstd/core/int/pow: (i : int, exp : int) -> int(ii: int,expexp: int) + +// Calculate ``2^exp``. +pub fip fun exp2std/core/int/exp2: (exp : int) -> int( expexp: int : intstd/core/types/int: V )result: -> total int : intstd/core/types/int: V + powstd/core/int/pow: (i : int, exp : int) -> int(2literal: int
dec = 2
hex8 = 0x02
bit8 = 0b00000010
,expexp: int
) + +// Return the number of ending `0` digits of `i`. Return `0` when `i==0`. +pub fip extern is-exp10std/core/int/is-exp10: (i : int) -> int( ii: int : intstd/core/types/int: V ) : intstd/core/types/int: V + c "kk_integer_ctz" + cs "Primitive.IntCountPow10" + js "$std_core_types._int_count_pow10" + +// Return the number of decimal digits of `i`. Return `0` when `i==0`. +pub fip extern count-digitsstd/core/int/count-digits: (i : int) -> int( ii: int : intstd/core/types/int: V ) : intstd/core/types/int: V + c "kk_integer_count_digits" + cs "Primitive.IntCountDigits" + js "$std_core_types._int_count_digits" + +pub fip extern mul-exp10std/core/int/mul-exp10: (i : int, n : int) -> int( ii: int : intstd/core/types/int: V, nn: int : intstd/core/types/int: V ) : intstd/core/types/int: V + c "kk_integer_mul_pow10" + cs "Primitive.IntMulPow10" + js "$std_core_types._int_mul_pow10" + +pub fip extern cdiv-exp10std/core/int/cdiv-exp10: (i : int, n : int) -> int( ii: int : intstd/core/types/int: V, nn: int : intstd/core/types/int: V ) : intstd/core/types/int: V + c "kk_integer_cdiv_pow10" + cs "Primitive.IntCDivPow10" + js "$std_core_types._int_cdiv_pow10" + +pub fun cdivmod-exp10std/core/int/cdivmod-exp10: (i : int, n : int) -> (int, int)( ii: int : intstd/core/types/int: V, nn: int : intstd/core/types/int: V )result: -> total (int, int) : (std/core/types/tuple2: (V, V) -> Vintstd/core/types/int: V,intstd/core/types/int: V) + if nn: int <=std/core/int/(<=): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
returnreturn: (int, int) (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)ii: int,0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b) + val cqcq: int = ii: int.cdiv-exp10std/core/int/cdiv-exp10: (i : int, n : int) -> int(nn: int) + val crcr: int = ii: int -std/core/int/(-): (x : int, y : int) -> int cqcq: int.mul-exp10std/core/int/mul-exp10: (i : int, n : int) -> int(nn: int) + (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)cqcq: int,crcr: int
)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b) + +pub fun divmod-exp10std/core/int/divmod-exp10: (i : int, n : int) -> (int, int)( ii: int : intstd/core/types/int: V, nn: int : intstd/core/types/int: V )result: -> total (int, int) : (std/core/types/tuple2: (V, V) -> Vintstd/core/types/int: V,intstd/core/types/int: V) + val (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)cqcq: int,crcr: int)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b) = cdivmod-exp10std/core/int/cdivmod-exp10: (i : int, n : int) -> (int, int)(ii: int,nn: int) + if !std/core/types/bool/(!): (b : bool) -> boolcrcr: int.is-negstd/core/int/is-neg: (i : int) -> bool then (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)cqcq: int,crcr: int)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b) else (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)cqcq: int.decstd/core/int/dec: (i : int) -> int, crcr: int +std/core/int/(+): (x : int, y : int) -> int exp10std/core/int/exp10: (exp : int) -> int(nn: int))std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b) + +// Is this an even integer? +pub fip fun is-evenstd/core/int/is-even: (i : int) -> bool(ii: int:intstd/core/types/int: V)result: -> total bool : boolstd/core/types/bool: V + !std/core/types/bool/(!): (b : bool) -> boolis-oddstd/core/int/is-odd: (i : int) -> bool(ii: int) + +// Is the integer positive (strictly greater than zero) +pub fip fun is-posstd/core/int/is-pos: (i : int) -> bool(ii: int : intstd/core/types/int: V )result: -> total bool : boolstd/core/types/bool: V + ii: int >std/core/int/(>): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
+ +// Is the integer negative (strictly smaller than zero) +pub fip fun is-negstd/core/int/is-neg: (i : int) -> bool(ii: int : intstd/core/types/int: V )result: -> total bool : boolstd/core/types/bool: V + ii: int <std/core/int/(<): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
+ +// Compare an integer `i` with zero +pub inline fip fun signstd/core/int/sign: (i : int) -> order( ^ii: int : intstd/core/types/int: V )result: -> total order : orderstd/core/types/order: V + cmpstd/core/int/cmp: (x : int, y : int) -> order(ii: int,0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) + // c inline "kk_int_as_order(kk_integer_signum_borrow(#1,kk_context()),kk_context())" + // cs "Primitive.IntSign" + // js "$std_core_types._int_sign" + +// Return the minimum of two integers +pub fip fun minstd/core/int/min: (i : int, j : int) -> int( ii: int : intstd/core/types/int: V, jj: int : intstd/core/types/int: V )result: -> total int : intstd/core/types/int: V + if ii: int <=std/core/int/(<=): (x : int, y : int) -> bool jj: int then ii: int else jj: int + +// Return the maximum of two integers +pub fip fun maxstd/core/int/max: (i : int, j : int) -> int( ii: int : intstd/core/types/int: V, jj: int : intstd/core/types/int: V )result: -> total int : intstd/core/types/int: V + if ii: int >=std/core/int/(>=): (x : int, y : int) -> bool jj: int then ii: int else jj: int + +// Transform an integer to a maybe type, using `Nothing` for `0` +pub fun maybestd/core/int/maybe: (i : int) -> maybe<int>( ii: int : intstd/core/types/int: V )result: -> total maybe<int> : maybestd/core/types/maybe: V -> V<intstd/core/types/int: V> + if ii: int==std/core/int/(==): (x : int, y : int) -> bool0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
then Nothingstd/core/types/Nothing: forall<a> maybe<a> else Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(ii: int
) + +// Convert an `:int` to a string +pub extern showstd/core/int/show: (i : int) -> string( ii: int : intstd/core/types/int: V ) : stringstd/core/types/string: V + c "kk_integer_to_string" + cs inline "#1.ToString()" + js inline "#1.toString()" + +// Convert an int to a boolean, using `False` for 0 and `True` otherwise. +pub fun boolstd/core/int/bool: (i : int) -> bool( ii: int : intstd/core/types/int: V )result: -> total bool : boolstd/core/types/bool: V + ii: int !=std/core/int/(!=): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
+ +// Convert a `:maybe<int>` to an `:int` using zero for `Nothing` +pub fip fun mbintstd/core/int/mbint: (m : maybe<int>) -> int( mm: maybe<int> : maybestd/core/types/maybe: V -> V<intstd/core/types/int: V> )result: -> total int : intstd/core/types/int: V + match mm: maybe<int> + Nothingstd/core/types/Nothing: forall<a> maybe<a> -> 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
+ Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(ii: int) ->
ii: int + + +// ---------------------------------------------------------------------------- +// Parse numbers +// ---------------------------------------------------------------------------- + +// Parse an integer using `parseInt`. If an illegal digit character is encountered the +// `default` value is returned. An empty string will also result in `default`. +// pub fun parse-int-default( s : string, def : int = 0, hex : bool = False ) : int +// if s.is-empty then def else s.parse-int(hex).default(def) + +// Parse an integer. +// If an illegal digit character is encountered `Nothing` is returned. +// An empty string, or a string starting with white space will result in `Nothing` +// A string can start with a `-` sign for negative numbers, +// and with `0x` or `0X` for hexadecimal numbers (in which case the `hex` parameter is ignored). +pub fun parse-intstd/core/int/parse-int: (s : string, hex : ? bool) -> maybe<int>( ss: string : stringstd/core/types/string: V, hexhex: ? bool : boolstd/core/types/bool: V = Falsestd/core/types/False: bool)result: -> total maybe<int> : maybestd/core/types/maybe: V -> V<intstd/core/types/int: V> + ss: string.xparsestd/core/int/xparse: (s : string, hex : bool) -> maybe<int>(hexhex: bool) + +noinline extern xparsestd/core/int/xparse: (s : string, hex : bool) -> maybe<int>( ss: string : stringstd/core/types/string: V, hexhex: bool : boolstd/core/types/bool: V ) : maybestd/core/types/maybe: V -> V<intstd/core/types/int: V> + c "kk_integer_xparse" + cs "Primitive.IntParse" + js "_int_parse" + + + +// ---------------------------------------------------------------------------- +// int8, int16, intptr_t +// ---------------------------------------------------------------------------- + +// clamp an `:int` to fit in an `:int8`. +pub fip extern int8std/core/int/int8: (i : int) -> int8( ii: int : intstd/core/types/int: V) : int8std/core/types/int8: V + c "kk_integer_clamp_int8" + cs "Primitive.IntToInt8" + js "$std_core_types._int_clamp8" + +// Convert an `:int8` to an `:int`. +pub inline fip extern int8/intstd/core/int/int8/int: (i : int8) -> int( i : int8std/core/types/int8: V ) : intstd/core/types/int: V + c "kk_integer_from_int8" + cs inline "(new BigInteger(#1))" + js "$std_core_types._int_from_int32" + + +// clamp an `:int` to fit in an `:int8` but interpret the `:int` as an unsigned 8-bit value, +// and clamp between 0 and 255. +pub fip extern uint8std/core/int/uint8: (i : int) -> int8( ii: int : intstd/core/types/int: V) : int8std/core/types/int8: V + c "kk_integer_clamp_byte" + cs "Primitive.IntToUInt8" + js "$std_core_types._int_clamp_byte" + +// Convert an `:int8` to an `:int` but interpret the `:int8` as an unsigned 8-bit value between 0 and 255. +pub inline fip extern int8/uintstd/core/int/int8/uint: (i : int8) -> int( i : int8std/core/types/int8: V ) : intstd/core/types/int: V + c "kk_integer_from_uint8" + cs inline "(new BigInteger(#1 >= 0 ? #1 : 256 + #1))" + js "$std_core_types._int_from_int32" + + +// clamp an `:int` to fit in an `:int16`. +pub fip extern int16std/core/int/int16: (i : int) -> int16( ii: int : intstd/core/types/int: V) : int16std/core/types/int16: V + c "kk_integer_clamp_int16" + cs "Primitive.IntToInt16" + js "$std_core_types._int_clamp16" + +// Convert an `:int16` to an `:int`. +pub inline fip extern int16/intstd/core/int/int16/int: (i : int16) -> int( i : int16std/core/types/int16: V ) : intstd/core/types/int: V + c "kk_integer_from_int16" + cs inline "(new BigInteger(#1))" + js "$std_core_types._int_from_int32" + + + +// clamp an `:int` to fit in an `:intptr_t`. +pub fip extern intptr_tstd/core/int/intptr_t: (i : int) -> intptr_t( ii: int : intstd/core/types/int: V) : intptr_tstd/core/types/intptr_t: V + c "kk_integer_clamp_intptr_t" + cs "Primitive.IntToInt64" + js "$std_core_types._int_clamp64" + +// Convert an `:intptr_t` to an `:int`. +pub inline fip extern intptr_t/intstd/core/int/intptr_t/int: (i : intptr_t) -> int( i : intptr_tstd/core/types/intptr_t: V ) : intstd/core/types/int: V + c "kk_integer_from_intptr_t" + cs inline "(new BigInteger(#1))" + js "$std_core_types._int_from_int64" + +// Convert an integer to an `:ssize_t`. The number is _clamped_ to the maximal or minimum `:ssize_t` +// value if it is outside the range of an `:ssize_t`. +// Needed for evidence indices in `module std/core/hnd` +pub fip extern ssize_tstd/core/int/ssize_t: (i : int) -> ssize_t( ii: int : intstd/core/types/int: V) : ssize_tstd/core/types/ssize_t: V + c "kk_integer_clamp_ssize_t" + cs "Primitive.IntToInt32" + js "$std_core_types._int_clamp32" + +// Convert an `:ssize_t` to an `:int`. +pub inline fip extern ssize_t/intstd/core/int/ssize_t/int: (i : ssize_t) -> int( i : ssize_tstd/core/types/ssize_t: V ) : intstd/core/types/int: V + c "kk_integer_from_ssize_t" + cs inline "(new BigInteger(#1))" + js "$std_core_types._int_from_int32"
diff --git a/doc/std_core_int.html b/doc/std_core_int.html index 94bdc1708..cebbcb1e4 100644 --- a/doc/std_core_int.html +++ b/doc/std_core_int.html @@ -15,10 +15,10 @@ -

std/core/int▲toc

+

std/core/int▲toc

-

Standard integer intstd/core/types/int: V functions.

+

Standard integer intstd/core/types/int: V functions.

@@ -32,101 +32,101 @@

Standard integer https://​www.​microsoft.​com/​en-​us/​research/​uploads/​prod/​2022/​07/​int.​pdf.

-
+ -
+ -
+
-

Convert an int8std/core/types/int8: V to an intstd/core/types/int: V but interpret the int8std/core/types/int8: V as an unsigned 8-bit value between 0 and 255. +

Convert an int8std/core/types/int8: V to an intstd/core/types/int: V but interpret the int8std/core/types/int8: V as an unsigned 8-bit value between 0 and 255.

-
+ -
+ -
+

Are two integers not equal?

-
+

Euclidean modulus of two integers; always a non-negative number. See also divmodstd/core/int/divmod: (x : int, y : int) -> (int, int).

-
+ -
+ -
+

Substract two integers.

-
+ -
+

Is the first integer smaller than the second?

-
+

Is the first integer smaller or equal to the second?

-
+

Are two integers equal?

-
+

Is the first integer greater than the second?

-
+

Is the first integer greater or equal to the second?

-
+

Raise an integer i to the power of exp.

-
+

Negate an integer.

-
+

Return the absolute value of an integer.

-
+
-

Convert an int to a boolean, using Falsestd/core/types/False: bool for 0 and Truestd/core/types/True: bool otherwise. +

Convert an int to a boolean, using Falsestd/core/types/False: bool for 0 and Truestd/core/types/True: bool otherwise.

- - -
+ + + -
+

Return the number of decimal digits of i. Return 0 when i(==)std/core/int/(==): (x : int, y : int) -> bool0.

-
+ -
+ - -
+ +

Calculate 10^exp.

-
+

Calculate 2^exp.

-
+ -
+ -
+ -
+ -
+

Is this an even integer?

-
+

Return the number of ending 0 digits of i. Return 0 when i(==)std/core/int/(==): (x : int, y : int) -> bool0.

-
+

Is the integer negative (strictly smaller than zero).

-
+

Is this an odd integer?

-
+

Is the integer positive (strictly greater than zero).

-
+

Is this equal to zero?

-
+

Return the maximum of two integers.

-
+
-

Transform an integer to a maybe type, using Nothingstd/core/types/Nothing: forall<a> maybe<a> for 0. +

Transform an integer to a maybe type, using Nothingstd/core/types/Nothing: forall<a> maybe<a> for 0.

-
+ -
+

Return the minimum of two integers.

- - - -
+ + + + -
+

Parse an integer. -If an illegal digit character is encountered Nothingstd/core/types/Nothing: forall<a> maybe<a> is returned. -An empty string, or a string starting with white space will result in Nothingstd/core/types/Nothing: forall<a> maybe<a> +If an illegal digit character is encountered Nothingstd/core/types/Nothing: forall<a> maybe<a> is returned. +An empty string, or a string starting with white space will result in Nothingstd/core/types/Nothing: forall<a> maybe<a> A string can start with a (-)std/core/int/(-): (x : int, y : int) -> int sign for negative numbers, and with 0x or 0X for hexadecimal numbers (in which case the hex parameter is ignored).

-
+

Raise an integer i to the power of exp.

-
+
-

Convert an intstd/core/types/int: V to a string. +

Convert an intstd/core/types/int: V to a string.

-
+

Compare an integer i with zero.

-
+
-

Convert an integer to an ssize_tstd/core/types/ssize_t: V. The number is clamped to the maximal or minimum ssize_tstd/core/types/ssize_t: V -value if it is outside the range of an ssize_tstd/core/types/ssize_t: V. -Needed for evidence indices in std/core/hnd. +

Convert an integer to an ssize_tstd/core/types/ssize_t: V. The number is clamped to the maximal or minimum ssize_tstd/core/types/ssize_t: V +value if it is outside the range of an ssize_tstd/core/types/ssize_t: V. +Needed for evidence indices in std/core/hnd.

-
+
-

Clamp an intstd/core/types/int: V to fit in an int8std/core/types/int8: V but interpret the intstd/core/types/int: V as an unsigned 8-bit value, +

Clamp an intstd/core/types/int: V to fit in an int8std/core/types/int8: V but interpret the intstd/core/types/int: V as an unsigned 8-bit value, and clamp between 0 and 255.

- + diff --git a/doc/std_core_list-source.html b/doc/std_core_list-source.html index 4b9698179..14ec93842 100644 --- a/doc/std_core_list-source.html +++ b/doc/std_core_list-source.html @@ -10,11 +10,552 @@ - documentation +list.kk documentation -

+
/*---------------------------------------------------------------------------
+  Copyright 2012-2024, Microsoft Research, Daan Leijen.
+
+  This is free software; you can redistribute it and/or modify it under the
+  terms of the Apache License, Version 2.0. A copy of the License can be
+  found in the LICENSE file at the root of this distribution.
+---------------------------------------------------------------------------*/
+
+// Standard `:list` functions.
+module std/core/liststd/core/list
+
+import std/core/typesstd/core/types
+import std/core/undivstd/core/undiv
+import std/core/hndstd/core/hnd
+import std/core/exnstd/core/exn
+import std/core/charstd/core/char
+import std/core/stringstd/core/string
+import std/core/intstd/core/int
+
+
+// Return the head of list if the list is not empty.
+pub fun headstd/core/list/head: forall<a> (xs : list<a>) -> maybe<a>( xsxs: list<$751> : liststd/core/types/list: V -> V<aa: V> )result: -> total maybe<772> : maybestd/core/types/maybe: V -> V<aa: V>
+  match xsxs: list<$751>
+    Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $751) -> Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: $751)
+    _       -> Nothingstd/core/types/Nothing: forall<a> maybe<a>
+
+// Return the head of list with a default value in case the list is empty.
+pub fun default/headstd/core/list/default/head: forall<a> (xs : list<a>, default : a) -> a( xsxs: list<$1225> : liststd/core/types/list: V -> V<aa: V>, defaultdefault: $1225 : aa: V )result: -> total 1238 : astd/core/types/total: E
+  match xsxs: list<$1225>
+    Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $1225) -> xx: $1225
+    _       -> defaultdefault: $1225
+
+// Return the tail of list. Returns the empty list if `xs` is empty.
+pub fun tailstd/core/list/tail: forall<a> (xs : list<a>) -> list<a>( xsxs: list<$1122> : liststd/core/types/list: V -> V<aa: V> )result: -> total list<1137> : liststd/core/types/list: V -> V<aa: V>
+  match xsxs: list<$1122>
+    Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(_,xxxx: list<$1122>) -> xxxx: list<$1122>
+    _          -> [std/core/types/Nil: forall<a> list<a>]std/core/types/Nil: forall<a> list<a>
+
+// Is the list empty?
+pub fun is-emptystd/core/list/is-empty: forall<a> (xs : list<a>) -> bool( xsxs: list<$841> : liststd/core/types/list: V -> V<aa: V> )result: -> total bool : boolstd/core/types/bool: V
+  match xsxs: list<$841>
+    Nilstd/core/types/Nil: forall<a> list<a> -> Truestd/core/types/True: bool
+    _   -> Falsestd/core/types/False: bool
+
+
+// ----------------------------------------------------------------------------
+// List functions
+// ----------------------------------------------------------------------------
+
+// Returns a singleton list.
+pub fun singlestd/core/list/single: forall<a> (x : a) -> list<a>(xx: _1104)result: -> total list<3221>
+  [std/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>xx: _1104]std/core/types/Nil: forall<a> list<a>
+
+// Returns the length of a list.
+pub fun lengthstd/core/list/length: forall<a> (xs : list<a>) -> int(xsxs: list<_890>)result: -> total int
+  fun lenlen: forall<a> (ys : list<a>, acc : int) -> int(ysys: list<_870>,accacc: int)result: -> total int
+    match ysys: list<_870>
+      Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(_,yyyy: list<_870>) -> yyyy: list<_870>.lenlen: (ys : list<_870>, acc : int) -> int(accacc: int+std/core/int/(+): (x : int, y : int) -> int1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
) + Nilstd/core/types/Nil: forall<a> list<a> -> accacc: int
+ xsxs: list<_890>.lenlen: (ys : list<_890>, acc : int) -> int(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) + +// Returns an integer list of increasing elements from `lo` to `hi` +// (including both `lo` and `hi` ). +// If `lo > hi` the function returns the empty list. +pub fun liststd/core/list/list: (lo : int, hi : int) -> list<int>( lolo: int: intstd/core/types/int: V, hihi: int: intstd/core/types/int: V )result: -> total list<int> : totalstd/core/types/total: E liststd/core/types/list: V -> V<intstd/core/types/int: V> + if lolo: int <=std/core/int/(<=): (x : int, y : int) -> bool hihi: int + then Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>( lolo: int, liststd/core/list/list: (lo : int, hi : int) -> list<int>( pretend-decreasingstd/core/undiv/pretend-decreasing: (x : int) -> int(lolo: int.incstd/core/int/inc: (i : int) -> int), hihi: int ) ) + else Nilstd/core/types/Nil: forall<a> list<a> + +// Returns an integer list of increasing elements from `lo` to `hi` with stride `stride`. +// If `lo > hi` the function returns the empty list. +pub fun stride/liststd/core/list/stride/list: (lo : int, hi : int, stride : int) -> list<int>( lolo: int: intstd/core/types/int: V, hihi: int: intstd/core/types/int: V, stridestride: int : intstd/core/types/int: V )result: -> total list<int> : totalstd/core/types/total: E liststd/core/types/list: V -> V<intstd/core/types/int: V> + if lolo: int <=std/core/int/(<=): (x : int, y : int) -> bool hihi: int + then Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>( lolo: int, liststd/core/list/stride/list: (lo : int, hi : int, stride : int) -> list<int>( pretend-decreasingstd/core/undiv/pretend-decreasing: (x : int) -> int(lolo: int +std/core/int/(+): (x : int, y : int) -> int stridestride: int), hihi: int, stridestride: int )) + else Nilstd/core/types/Nil: forall<a> list<a> + +// Applies a function `f` to list of increasing elements from `lo` to `hi` +// (including both `lo` and `hi` ). +// If `lo > hi` the function returns the empty list. +pub fun function/liststd/core/list/function/list: forall<a,e> (lo : int, hi : int, f : (int) -> e a) -> e list<a>( lolo: int: intstd/core/types/int: V, hihi: int: intstd/core/types/int: V, ff: (int) -> $2763 $2762 : intstd/core/types/int: V -> ee: E aa: V )result: -> 2812 list<2811> : ee: E liststd/core/types/list: V -> V<aa: V> + if lolo: int <=std/core/int/(<=): (x : int, y : int) -> $2763 bool hihi: int + then Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>( ff: (int) -> $2763 $2762(lolo: int), liststd/core/list/function/list: (lo : int, hi : int, f : (int) -> $2763 $2762) -> $2763 list<$2762>( pretend-decreasingstd/core/undiv/pretend-decreasing: (x : int) -> $2763 int(lolo: int.incstd/core/int/inc: (i : int) -> $2763 int), hihi: int, ff: (int) -> $2763 $2762 )) + else Nilstd/core/types/Nil: forall<a> list<a> + +// Returns an integer list of increasing elements from `lo` to `hi` with stride `stride`. +// If `lo > hi` the function returns the empty list. +pub fun stridefunction/liststd/core/list/stridefunction/list: forall<a,e> (lo : int, hi : int, stride : int, f : (int) -> e a) -> e list<a>( lolo: int: intstd/core/types/int: V, hihi: int: intstd/core/types/int: V, stridestride: int : intstd/core/types/int: V, ff: (int) -> $2875 $2874 : intstd/core/types/int: V -> ee: E aa: V )result: -> 2926 list<2925> : ee: E liststd/core/types/list: V -> V<aa: V> + if lolo: int <=std/core/int/(<=): (x : int, y : int) -> $2875 bool hihi: int + then Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>( ff: (int) -> $2875 $2874(lolo: int), liststd/core/list/stridefunction/list: (lo : int, hi : int, stride : int, f : (int) -> $2875 $2874) -> $2875 list<$2874>( pretend-decreasingstd/core/undiv/pretend-decreasing: (x : int) -> $2875 int(lolo: int +std/core/int/(+): (x : int, y : int) -> $2875 int stridestride: int), hihi: int, stridestride: int, ff: (int) -> $2875 $2874 )) + else Nilstd/core/types/Nil: forall<a> list<a> + +// Create a list of characters from `lo` to `hi` (including `hi`). +pub fun char/liststd/core/list/char/list: (lo : char, hi : char) -> list<char>( lolo: char : charstd/core/types/char: V, hihi: char : charstd/core/types/char: V )result: -> total list<char> : totalstd/core/types/total: E liststd/core/types/list: V -> V<charstd/core/types/char: V> + liststd/core/list/list: (lo : int, hi : int) -> list<int>(lolo: char.intstd/core/char/int: (char) -> int, hihi: char.intstd/core/char/int: (char) -> int).mapstd/core/list/map: (xs : list<int>, f : (int) -> char) -> list<char>( charstd/core/char/int/char: (i : int) -> char ) + +// Element-wise list equality +pub fun (==)std/core/list/(==): forall<a> (xs : list<a>, ys : list<a>, @implicit/(==) : (a, a) -> bool) -> bool( xsxs: list<$1294> : liststd/core/types/list: V -> V<aa: V>, ysys: list<$1294> : liststd/core/types/list: V -> V<aa: V>, (@implicit/==)?(==): ($1294, $1294) -> bool : (aa: V,aa: V) -> boolstd/core/types/bool: V )result: -> total bool : boolstd/core/types/bool: V + match xsxs: list<$1294> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $1294,xxxx: list<$1294>) -> match ysys: list<$1294> + Nilstd/core/types/Nil: forall<a> list<a> -> Falsestd/core/types/False: bool + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $1294,yyyy: list<$1294>) -> (xx: $1294==?(==): ($1294, $1294) -> boolyy: $1294) &&std/core/types/(&&): (x : bool, y : bool) -> bool (xxxx: list<$1294>==std/core/list/(==): (xs : list<$1294>, ys : list<$1294>, @implicit/(==) : ($1294, $1294) -> bool) -> bool
?(==)=?(==)
yyyy: list<$1294>) + Nilstd/core/types/Nil: forall<a> list<a> -> match ysys: list<$1294> + Nilstd/core/types/Nil: forall<a> list<a> -> Truestd/core/types/True: bool + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a> -> Falsestd/core/types/False: bool
+ +// Order on lists +pub fun cmpstd/core/list/cmp: forall<a> (xs : list<a>, ys : list<a>, @implicit/cmp : (a, a) -> order) -> order( xsxs: list<$1507> : liststd/core/types/list: V -> V<aa: V>, ysys: list<$1507> : liststd/core/types/list: V -> V<aa: V>, @implicit/cmp?cmp: ($1507, $1507) -> order : (aa: V,aa: V) -> orderstd/core/types/order: V )result: -> total order : orderstd/core/types/order: V + match xsxs: list<$1507> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $1507,xxxx: list<$1507>) -> match ysys: list<$1507> + Nilstd/core/types/Nil: forall<a> list<a> -> Gtstd/core/types/Gt: order + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $1507,yyyy: list<$1507>) -> match cmp?cmp: ($1507, $1507) -> order(xx: $1507,yy: $1507) + Eqstd/core/types/Eq: order -> cmpstd/core/list/cmp: (xs : list<$1507>, ys : list<$1507>, @implicit/cmp : ($1507, $1507) -> order) -> order
?cmp=?cmp
(xxxx: list<$1507>,yyyy: list<$1507>) + lglg: order -> lglg: order + Nilstd/core/types/Nil: forall<a> list<a> -> match ysys: list<$1507> + Nilstd/core/types/Nil: forall<a> list<a> -> Eqstd/core/types/Eq: order + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a> -> Ltstd/core/types/Lt: order
+ + +// Show a list +pub fun showstd/core/list/show: forall<a,e> (xs : list<a>, @implicit/show : (a) -> e string) -> e string( xsxs: list<$3582> : liststd/core/types/list: V -> V<aa: V>, @implicit/show?show: ($3582) -> $3583 string : aa: V -> ee: E stringstd/core/types/string: V )result: -> 3644 string : ee: E stringstd/core/types/string: V + "["literal: string
count= 1
++std/core/types/(++): (x : string, y : string) -> $3583 string xsxs: list<$3582>.mapstd/core/list/map: (xs : list<$3582>, f : ($3582) -> $3583 string) -> $3583 list<string>(show?show: ($3582) -> $3583 string).joinstd/core/list/joinsep/join: (xs : list<string>, sep : string) -> $3583 string(","literal: string
count= 1
) ++std/core/types/(++): (x : string, y : string) -> $3583 string "]"literal: string
count= 1
+ + +// _deprecated_, use `list/show` instead. +pub fun show-liststd/core/list/show-list: forall<a,e> (xs : list<a>, show-elem : (a) -> e string) -> e string( xsxs: list<$3661> : liststd/core/types/list: V -> V<aa: V>, show-elemshow-elem: ($3661) -> $3662 string : (aa: V) -> ee: E stringstd/core/types/string: V )result: -> 3679 string : ee: E stringstd/core/types/string: V + showstd/core/list/show: (xs : list<$3661>, @implicit/show : ($3661) -> $3662 string) -> $3662 string(xsxs: list<$3661>,@implicit/show=show-elemshow-elem: ($3661) -> $3662 string) + + + +// Zip two lists together by pairing the corresponding elements. +// The returned list is only as long as the smallest input list. +pub fun zipstd/core/list/zip: forall<a,b> (xs : list<a>, ys : list<b>) -> list<(a, b)>( xsxs: list<$4650> : liststd/core/types/list: V -> V<aa: V>, ysys: list<$4651> : liststd/core/types/list: V -> V<bb: V> )result: -> total list<(4706, 4707)> : liststd/core/types/list: V -> V<(std/core/types/tuple2: (V, V) -> Vaa: V,bb: V)> + match xsxs: list<$4650> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $4650,xxxx: list<$4650>) -> match ysys: list<$4651> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $4651,yyyy: list<$4651>) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>((std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)xx: $4650,yy: $4651)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b),zipstd/core/list/zip: (xs : list<$4650>, ys : list<$4651>) -> list<($4650, $4651)>(xxxx: list<$4650>,yyyy: list<$4651>)) + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a> + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a> + +// Zip two lists together by apply a function `f` to all corresponding elements. +// The returned list is only as long as the smallest input list. +pub fun zipwithstd/core/list/zipwith: forall<a,b,c,e> (xs : list<a>, ys : list<b>, f : (a, b) -> e c) -> e list<c>( xsxs: list<$4715> : liststd/core/types/list: V -> V<aa: V>, ysys: list<$4716> :liststd/core/types/list: V -> V<bb: V>, ff: ($4715, $4716) -> $4718 $4717 : (aa: V,bb: V) -> ee: E cc: V )result: -> 4775 list<4774> : ee: E liststd/core/types/list: V -> V<cc: V> + match xsxs: list<$4715> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $4715,xxxx: list<$4715>) -> match ysys: list<$4716> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $4716,yyyy: list<$4716>) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(ff: ($4715, $4716) -> $4718 $4717(xx: $4715,yy: $4716),zipwithstd/core/list/zipwith: (xs : list<$4715>, ys : list<$4716>, f : ($4715, $4716) -> $4718 $4717) -> $4718 list<$4717>(xxxx: list<$4715>,yyyy: list<$4716>,ff: ($4715, $4716) -> $4718 $4717)) + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a> + _ -> Nilstd/core/types/Nil: forall<a> list<a> + +// Zip two lists together by apply a function `f` to all corresponding elements +// and their index in the list. +// The returned list is only as long as the smallest input list. +pub fun zipwith-indexedstd/core/list/zipwith-indexed: forall<a,b,c,e> (xs0 : list<a>, ys0 : list<b>, f : (int, a, b) -> e c) -> e list<c>( xs0xs0: list<$1142> : liststd/core/types/list: V -> V<aa: V>, ys0ys0: list<$1143> :liststd/core/types/list: V -> V<bb: V>, ff: (int, $1142, $1143) -> $1145 $1144 : (intstd/core/types/int: V,aa: V,bb: V) -> ee: E cc: V )result: -> 1212 list<1211> : ee: E liststd/core/types/list: V -> V<cc: V> + fun zipwith-iterzipwith-iter: (i : int, xs : list<$1142>, ys : list<$1143>) -> $1145 list<$1144>( ii: int, xsxs: list<$1142>, ysys: list<$1143> )result: -> $1145 list<$1144> + match xsxs: list<$1142> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $1142,xxxx: list<$1142>) -> match ysys: list<$1143> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $1143,yyyy: list<$1143>) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(ff: (int, $1142, $1143) -> $1145 $1144(ii: int,xx: $1142,yy: $1143),zipwith-iterzipwith-iter: (i : int, xs : list<$1142>, ys : list<$1143>) -> $1145 list<$1144>(ii: int+std/core/int/(+): (x : int, y : int) -> $1145 int1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
,xxxx: list<$1142>,yyyy: list<$1143>)) + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a> + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a>
+ zipwith-iterzipwith-iter: (i : int, xs : list<$1142>, ys : list<$1143>) -> $1145 list<$1144>(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
,xs0xs0: list<$1142>,ys0ys0: list<$1143>
) + +// Unzip a list of pairs into two lists +pub fun unzipstd/core/list/unzip: forall<a,b> (xs : list<(a, b)>) -> (list<a>, list<b>)( xsxs: list<($3849, $3850)> : liststd/core/types/list: V -> V<(std/core/types/tuple2: (V, V) -> Vaa: V,bb: V)> )result: -> total (list<4027>, list<4028>) : (std/core/types/tuple2: (V, V) -> Vliststd/core/types/list: V -> V<aa: V>,liststd/core/types/list: V -> V<bb: V>) + // todo: implement TRMC for multiple results + fun iteriter: forall<a,b,c,d> (ys : list<(a, b)>, acc1 : cctx<c,list<a>>, acc2 : cctx<d,list<b>>) -> (c, d)( ysys: list<(_3864, _3865)>, acc1acc1: cctx<_3906,list<_3864>>, acc2acc2: cctx<_3946,list<_3865>> )result: -> total (_3906, _3946) + match ysys: list<(_3864, _3865)> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>((std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)xx: _3864,yy: _3865)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b),xxxx: list<(_3864, _3865)>) -> iteriter: (ys : list<(_3864, _3865)>, acc1 : cctx<_3906,list<_3864>>, acc2 : cctx<_3946,list<_3865>>) -> (_3906, _3946)(xxxx: list<(_3864, _3865)>,acc1acc1: cctx<_3906,list<_3864>> ++std/core/types/cctx/(++): (c1 : cctx<_3906,list<_3864>>, c2 : cctx<list<_3864>,list<_3864>>) -> cctx<_3906,list<_3864>> ctxctx: cctx<list<_3864>,list<_3864>> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: _3864,_hole: list<_3864>),acc2acc2: cctx<_3946,list<_3865>> ++std/core/types/cctx/(++): (c1 : cctx<_3946,list<_3865>>, c2 : cctx<list<_3865>,list<_3865>>) -> cctx<_3946,list<_3865>> ctxctx: cctx<list<_3865>,list<_3865>> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: _3865,_hole: list<_3865>)) + Nilstd/core/types/Nil: forall<a> list<a> -> (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)acc1acc1: cctx<_3906,list<_3864>> ++.std/core/types/cctx/(++.): (c : cctx<_3906,list<_3864>>, x : list<_3864>) -> _3906 Nilstd/core/types/Nil: forall<a> list<a>,acc2acc2: cctx<_3946,list<_3865>> ++.std/core/types/cctx/(++.): (c : cctx<_3946,list<_3865>>, x : list<_3865>) -> _3946 Nilstd/core/types/Nil: forall<a> list<a>)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b) + iteriter: (ys : list<($3849, $3850)>, acc1 : cctx<list<$3849>,list<$3849>>, acc2 : cctx<list<$3850>,list<$3850>>) -> (list<$3849>, list<$3850>)(xsxs: list<($3849, $3850)>,ctxctx: ctx<list<$3849>> _hole: list<$3849>,ctxctx: ctx<list<$3850>> _hole: list<$3850>) + +// Unzip a list of triples into three lists +pub fun unzip3std/core/list/unzip3: forall<a,b,c> (xs : list<(a, b, c)>) -> (list<a>, list<b>, list<c>)( xsxs: list<($4036, $4037, $4038)> : liststd/core/types/list: V -> V<(std/core/types/tuple3: (V, V, V) -> Vaa: V,bb: V,cc: V)>)result: -> total (list<4290>, list<4291>, list<4292>) : (std/core/types/tuple3: (V, V, V) -> Vliststd/core/types/list: V -> V<aa: V>,liststd/core/types/list: V -> V<bb: V>,liststd/core/types/list: V -> V<cc: V>) + // todo: implement TRMC for multiple results + fun iteriter: forall<a,b,c,d,a1,b1> (ys : list<(a, b, c)>, acc1 : cctx<d,list<a>>, acc2 : cctx<a1,list<b>>, acc3 : cctx<b1,list<c>>) -> (d, a1, b1)( ysys: list<(_4054, _4055, _4056)>, acc1acc1: cctx<_4097,list<_4054>>, acc2acc2: cctx<_4137,list<_4055>>, acc3acc3: cctx<_4177,list<_4056>> )result: -> total (_4097, _4137, _4177) + match ysys: list<(_4054, _4055, _4056)> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>((std/core/types/Tuple3: forall<a,b,c> (fst : a, snd : b, thd : c) -> (a, b, c)xx: _4054,yy: _4055,zz: _4056)std/core/types/Tuple3: forall<a,b,c> (fst : a, snd : b, thd : c) -> (a, b, c),xxxx: list<(_4054, _4055, _4056)>) -> iteriter: (ys : list<(_4054, _4055, _4056)>, acc1 : cctx<_4097,list<_4054>>, acc2 : cctx<_4137,list<_4055>>, acc3 : cctx<_4177,list<_4056>>) -> (_4097, _4137, _4177)(xxxx: list<(_4054, _4055, _4056)>,acc1acc1: cctx<_4097,list<_4054>> ++std/core/types/cctx/(++): (c1 : cctx<_4097,list<_4054>>, c2 : cctx<list<_4054>,list<_4054>>) -> cctx<_4097,list<_4054>> ctxctx: cctx<list<_4054>,list<_4054>> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: _4054,_hole: list<_4054>),acc2acc2: cctx<_4137,list<_4055>> ++std/core/types/cctx/(++): (c1 : cctx<_4137,list<_4055>>, c2 : cctx<list<_4055>,list<_4055>>) -> cctx<_4137,list<_4055>> ctxctx: cctx<list<_4055>,list<_4055>> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: _4055,_hole: list<_4055>),acc3acc3: cctx<_4177,list<_4056>> ++std/core/types/cctx/(++): (c1 : cctx<_4177,list<_4056>>, c2 : cctx<list<_4056>,list<_4056>>) -> cctx<_4177,list<_4056>> ctxctx: cctx<list<_4056>,list<_4056>> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(zz: _4056,_hole: list<_4056>)) + Nilstd/core/types/Nil: forall<a> list<a> -> (std/core/types/Tuple3: forall<a,b,c> (fst : a, snd : b, thd : c) -> (a, b, c)acc1acc1: cctx<_4097,list<_4054>> ++.std/core/types/cctx/(++.): (c : cctx<_4097,list<_4054>>, x : list<_4054>) -> _4097 Nilstd/core/types/Nil: forall<a> list<a>,acc2acc2: cctx<_4137,list<_4055>> ++.std/core/types/cctx/(++.): (c : cctx<_4137,list<_4055>>, x : list<_4055>) -> _4137 Nilstd/core/types/Nil: forall<a> list<a>,acc3acc3: cctx<_4177,list<_4056>> ++.std/core/types/cctx/(++.): (c : cctx<_4177,list<_4056>>, x : list<_4056>) -> _4177 Nilstd/core/types/Nil: forall<a> list<a>)std/core/types/Tuple3: forall<a,b,c> (fst : a, snd : b, thd : c) -> (a, b, c) + iteriter: (ys : list<($4036, $4037, $4038)>, acc1 : cctx<list<$4036>,list<$4036>>, acc2 : cctx<list<$4037>,list<$4037>>, acc3 : cctx<list<$4038>,list<$4038>>) -> (list<$4036>, list<$4037>, list<$4038>)(xsxs: list<($4036, $4037, $4038)>,ctxctx: ctx<list<$4036>> _hole: list<$4036>,ctxctx: ctx<list<$4037>> _hole: list<$4037>,ctxctx: ctx<list<$4038>> _hole: list<$4038>) + +// Unzip a list of quadruples into four lists +pub fun unzip4std/core/list/unzip4: forall<a,b,c,d> (xs : list<(a, b, c, d)>) -> (list<a>, list<b>, list<c>, list<d>)( xsxs: list<($4303, $4304, $4305, $4306)> : liststd/core/types/list: V -> V<(std/core/types/tuple4: (V, V, V, V) -> Vaa: V,bb: V,cc: V,dd: V)>)result: -> total (list<4633>, list<4634>, list<4635>, list<4636>) : (std/core/types/tuple4: (V, V, V, V) -> Vliststd/core/types/list: V -> V<aa: V>,liststd/core/types/list: V -> V<bb: V>,liststd/core/types/list: V -> V<cc: V>,liststd/core/types/list: V -> V<dd: V>) + // todo: implement TRMC for multiple results + fun iteriter: forall<a,b,c,d,a1,b1,c1,d1> (ys : list<(a, b, c, d)>, acc1 : cctx<a1,list<a>>, acc2 : cctx<b1,list<b>>, acc3 : cctx<c1,list<c>>, acc4 : cctx<d1,list<d>>) -> (a1, b1, c1, d1)( ysys: list<(_4324, _4325, _4326, _4327)>, acc1acc1: cctx<_4368,list<_4324>>, acc2acc2: cctx<_4408,list<_4325>>, acc3acc3: cctx<_4448,list<_4326>>, acc4acc4: cctx<_4488,list<_4327>> )result: -> total (_4368, _4408, _4448, _4488) + match ysys: list<(_4324, _4325, _4326, _4327)> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>((std/core/types/Tuple4: forall<a,b,c,d> (fst : a, snd : b, thd : c, field4 : d) -> (a, b, c, d)xx: _4324,yy: _4325,zz: _4326,ww: _4327)std/core/types/Tuple4: forall<a,b,c,d> (fst : a, snd : b, thd : c, field4 : d) -> (a, b, c, d),xxxx: list<(_4324, _4325, _4326, _4327)>) -> iteriter: (ys : list<(_4324, _4325, _4326, _4327)>, acc1 : cctx<_4368,list<_4324>>, acc2 : cctx<_4408,list<_4325>>, acc3 : cctx<_4448,list<_4326>>, acc4 : cctx<_4488,list<_4327>>) -> (_4368, _4408, _4448, _4488)(xxxx: list<(_4324, _4325, _4326, _4327)>,acc1acc1: cctx<_4368,list<_4324>> ++std/core/types/cctx/(++): (c1 : cctx<_4368,list<_4324>>, c2 : cctx<list<_4324>,list<_4324>>) -> cctx<_4368,list<_4324>> ctxctx: cctx<list<_4324>,list<_4324>> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: _4324,_hole: list<_4324>),acc2acc2: cctx<_4408,list<_4325>> ++std/core/types/cctx/(++): (c1 : cctx<_4408,list<_4325>>, c2 : cctx<list<_4325>,list<_4325>>) -> cctx<_4408,list<_4325>> ctxctx: cctx<list<_4325>,list<_4325>> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: _4325,_hole: list<_4325>),acc3acc3: cctx<_4448,list<_4326>> ++std/core/types/cctx/(++): (c1 : cctx<_4448,list<_4326>>, c2 : cctx<list<_4326>,list<_4326>>) -> cctx<_4448,list<_4326>> ctxctx: cctx<list<_4326>,list<_4326>> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(zz: _4326,_hole: list<_4326>),acc4acc4: cctx<_4488,list<_4327>> ++std/core/types/cctx/(++): (c1 : cctx<_4488,list<_4327>>, c2 : cctx<list<_4327>,list<_4327>>) -> cctx<_4488,list<_4327>> ctxctx: cctx<list<_4327>,list<_4327>> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(ww: _4327,_hole: list<_4327>)) + Nilstd/core/types/Nil: forall<a> list<a> -> (std/core/types/Tuple4: forall<a,b,c,d> (fst : a, snd : b, thd : c, field4 : d) -> (a, b, c, d)acc1acc1: cctx<_4368,list<_4324>> ++.std/core/types/cctx/(++.): (c : cctx<_4368,list<_4324>>, x : list<_4324>) -> _4368 Nilstd/core/types/Nil: forall<a> list<a>,acc2acc2: cctx<_4408,list<_4325>> ++.std/core/types/cctx/(++.): (c : cctx<_4408,list<_4325>>, x : list<_4325>) -> _4408 Nilstd/core/types/Nil: forall<a> list<a>,acc3acc3: cctx<_4448,list<_4326>> ++.std/core/types/cctx/(++.): (c : cctx<_4448,list<_4326>>, x : list<_4326>) -> _4448 Nilstd/core/types/Nil: forall<a> list<a>,acc4acc4: cctx<_4488,list<_4327>> ++.std/core/types/cctx/(++.): (c : cctx<_4488,list<_4327>>, x : list<_4327>) -> _4488 Nilstd/core/types/Nil: forall<a> list<a>)std/core/types/Tuple4: forall<a,b,c,d> (fst : a, snd : b, thd : c, field4 : d) -> (a, b, c, d) + iteriter: (ys : list<($4303, $4304, $4305, $4306)>, acc1 : cctx<list<$4303>,list<$4303>>, acc2 : cctx<list<$4304>,list<$4304>>, acc3 : cctx<list<$4305>,list<$4305>>, acc4 : cctx<list<$4306>,list<$4306>>) -> (list<$4303>, list<$4304>, list<$4305>, list<$4306>)(xsxs: list<($4303, $4304, $4305, $4306)>,ctxctx: ctx<list<$4303>> _hole: list<$4303>,ctxctx: ctx<list<$4304>> _hole: list<$4304>,ctxctx: ctx<list<$4305>> _hole: list<$4305>,ctxctx: ctx<list<$4306>> _hole: list<$4306>) + +// Take the first `n` elements of a list (or fewer if the list is shorter than `n`) +pub fun takestd/core/list/take: forall<a> (xs : list<a>, n : int) -> list<a>( xsxs: list<$2574> : liststd/core/types/list: V -> V<aa: V>, nn: int : intstd/core/types/int: V )result: -> total list<2612> : liststd/core/types/list: V -> V<aa: V> + match xsxs: list<$2574> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $2574,xxxx: list<$2574>) | nn: int >std/core/int/(>): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
-> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $2574, takestd/core/list/take: (xs : list<$2574>, n : int) -> list<$2574>(xxxx: list<$2574>, nn: int -std/core/int/(-): (x : int, y : int) -> int 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
)) + _ -> Nilstd/core/types/Nil: forall<a> list<a>
+ +// Drop the first `n` elements of a list (or fewer if the list is shorter than `n`) +pub fun dropstd/core/list/drop: forall<a> (xs : list<a>, n : int) -> list<a>( xsxs: list<$1621> : liststd/core/types/list: V -> V<aa: V>, nn: int : intstd/core/types/int: V )result: -> total list<1650> : liststd/core/types/list: V -> V<aa: V> + match xsxs: list<$1621> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(_,xxxx: list<$1621>) | nn: int >std/core/int/(>): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
-> dropstd/core/list/drop: (xs : list<$1621>, n : int) -> list<$1621>(xxxx: list<$1621>, nn: int -std/core/int/(-): (x : int, y : int) -> int 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
) + _ -> xsxs: list<$1621>
+ +// Apply a function `f` to each element of the input list in sequence. +pub fun mapstd/core/list/map: forall<a,b,e> (xs : list<a>, f : (a) -> e b) -> e list<b>(xsxs: list<$2967> : liststd/core/types/list: V -> V<aa: V>, ff: ($2967) -> $2969 $2968 : aa: V -> ee: E bb: V)result: -> 3011 list<3010> : ee: E liststd/core/types/list: V -> V<bb: V> + match xsxs: list<$2967> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $2967,xxxx: list<$2967>) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(ff: ($2967) -> $2969 $2968(xx: $2967), xxxx: list<$2967>.mapstd/core/list/map: (xs : list<$2967>, f : ($2967) -> $2969 $2968) -> $2969 list<$2968>(ff: ($2967) -> $2969 $2968)) + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a> + +// Apply a function `f` to each element of the input list in sequence where takes +// both the index of the current element and the element itself as arguments. +pub fun map-indexedstd/core/list/map-indexed: forall<a,b,e> (xs : list<a>, f : (idx : int, value : a) -> e b) -> e list<b>(xsxs: list<$929> : liststd/core/types/list: V -> V<aa: V>, ff: (idx : int, value : $929) -> $931 $930 : (idx : intstd/core/types/int: V, value : aa: V) -> ee: E bb: V)result: -> 980 list<979> : ee: E liststd/core/types/list: V -> V<bb: V> + fun map-idxmap-idx: (ys : list<$929>, i : int) -> $931 list<$930>(ysys: list<$929>,ii: int)result: -> $931 list<$930> + match ysys: list<$929> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $929,yyyy: list<$929>) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(ff: (idx : int, value : $929) -> $931 $930(ii: int,yy: $929), map-idxmap-idx: (ys : list<$929>, i : int) -> $931 list<$930>(yyyy: list<$929>,ii: int+std/core/int/(+): (x : int, y : int) -> $931 int1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
)) + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a>
+ map-idxmap-idx: (ys : list<$929>, i : int) -> $931 list<$930>(xsxs: list<$929>,0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) + +// Apply a function `f` to each element of the input list in sequence where `f` takes +// both the current element and the tail list as arguments. +pub fun map-peekstd/core/list/map-peek: forall<a,b,e> (xs : list<a>, f : (value : a, rest : list<a>) -> e b) -> e list<b>(xsxs: list<$1052> : liststd/core/types/list: V -> V<aa: V>, ff: (value : $1052, rest : list<$1052>) -> $1054 $1053 : (value : aa: V, rest : liststd/core/types/list: V -> V<aa: V>) -> ee: E bb: V)result: -> 1094 list<1093> : ee: E liststd/core/types/list: V -> V<bb: V> + fun mappeekmappeek: (ys : list<$1052>) -> $1054 list<$1053>(ysys: list<$1052>)result: -> $1054 list<$1053> + match ysys: list<$1052> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $1052,yyyy: list<$1052>) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(ff: (value : $1052, rest : list<$1052>) -> $1054 $1053(yy: $1052,yyyy: list<$1052>), yyyy: list<$1052>.mappeekmappeek: (ys : list<$1052>) -> $1054 list<$1053>) + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a> + mappeekmappeek: (ys : list<$1052>) -> $1054 list<$1053>(xsxs: list<$1052>) + +// Apply a function `f` to each element of the input list in sequence where takes +// both the index of the current element, the element itself, and the tail list as arguments. +pub fun map-indexed-peekstd/core/list/map-indexed-peek: forall<a,b,e> (xs : list<a>, f : (idx : int, value : a, rest : list<a>) -> e b) -> e list<b>(xsxs: list<$990> : liststd/core/types/list: V -> V<aa: V>, ff: (idx : int, value : $990, rest : list<$990>) -> $992 $991 : (idx : intstd/core/types/int: V, value : aa: V, rest : liststd/core/types/list: V -> V<aa: V> ) -> ee: E bb: V)result: -> 1042 list<1041> : ee: E liststd/core/types/list: V -> V<bb: V> + fun mapidxmapidx: (ys : list<$990>, i : int) -> $992 list<$991>(ysys: list<$990>,ii: int)result: -> $992 list<$991> + match ysys: list<$990> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $990,yyyy: list<$990>) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(ff: (idx : int, value : $990, rest : list<$990>) -> $992 $991(ii: int,yy: $990,yyyy: list<$990>), mapidxmapidx: (ys : list<$990>, i : int) -> $992 list<$991>(yyyy: list<$990>,ii: int+std/core/int/(+): (x : int, y : int) -> $992 int1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
)) + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a>
+ mapidxmapidx: (ys : list<$990>, i : int) -> $992 list<$991>(xsxs: list<$990>,0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) + +// Reverse a list. +pub fun reversestd/core/list/reverse: forall<a> (xs : list<a>) -> list<a>(xsxs: list<$2109> : liststd/core/types/list: V -> V<aa: V>)result: -> total list<2124> : liststd/core/types/list: V -> V<aa: V> + reverse-appendstd/core/list/reverse-append: (xs : list<$2109>, tl : list<$2109>) -> list<$2109>( xsxs: list<$2109>, Nilstd/core/types/Nil: forall<a> list<a> ) + +// Efficiently reverse a list `xs` and append it to `tl`: +// `reverse-append(xs,tl) == reserve(xs) ++ tl +pub fun reverse-appendstd/core/list/reverse-append: forall<a> (xs : list<a>, tl : list<a>) -> list<a>( xsxs: list<$701> : liststd/core/types/list: V -> V<aa: V>, tltl: list<$701> : liststd/core/types/list: V -> V<aa: V> )result: -> total list<746> : liststd/core/types/list: V -> V<aa: V> + fun reverse-accreverse-acc: forall<a> (acc : list<a>, ys : list<a>) -> list<a>(accacc: list<$702> : liststd/core/types/list: V -> V<aa: V>, ysys: list<$702> : liststd/core/types/list: V -> V<aa: V> )result: -> total list<729> : liststd/core/types/list: V -> V<aa: V> + match ysys: list<$702> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $702,xxxx: list<$702>) -> reverse-accreverse-acc: (acc : list<$702>, ys : list<$702>) -> list<$702>(Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $702,accacc: list<$702>),xxxx: list<$702>) + _ -> accacc: list<$702> + reverse-accreverse-acc: (acc : list<$701>, ys : list<$701>) -> list<$701>(tltl: list<$701>,xsxs: list<$701>) + +// Append two lists. +pub fun (++)std/core/list/(++): forall<a> (xs : list<a>, ys : list<a>) -> list<a>(xsxs: list<$1276> : liststd/core/types/list: V -> V<aa: V>, ysys: list<$1276> : liststd/core/types/list: V -> V<aa: V> )result: -> total list<1289> : liststd/core/types/list: V -> V<aa: V> + appendstd/core/list/append: (xs : list<$1276>, ys : list<$1276>) -> list<$1276>(xsxs: list<$1276>,ysys: list<$1276>) + +// Append two lists. +pub fun appendstd/core/list/append: forall<a> (xs : list<a>, ys : list<a>) -> list<a>(xsxs: list<$1243> : liststd/core/types/list: V -> V<aa: V>, ysys: list<$1243> : liststd/core/types/list: V -> V<aa: V> )result: -> total list<1271> : liststd/core/types/list: V -> V<aa: V> + match xsxs: list<$1243> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $1243,xxxx: list<$1243>) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $1243,appendstd/core/list/append: (xs : list<$1243>, ys : list<$1243>) -> list<$1243>(xxxx: list<$1243>,ysys: list<$1243>)) + Nilstd/core/types/Nil: forall<a> list<a> -> ysys: list<$1243> + +// Fold a list from the right, i.e. `foldr([1,2],0,(+)) == 1+(2+0)` +// Note, `foldr` is less efficient than `foldl` as it reverses the list first. +pub fun foldrstd/core/list/foldr: forall<a,b,e> (xs : list<a>, z : b, f : (a, b) -> e b) -> e b(xsxs: list<$2129> : liststd/core/types/list: V -> V<aa: V>, zz: $2130 : bb: V, ff: ($2129, $2130) -> $2131 $2130 : (aa: V, bb: V) -> ee: E bb: V)result: -> 2163 2162 : ee: E bb: V + xsxs: list<$2129>.reversestd/core/list/reverse: (xs : list<$2129>) -> $2131 list<$2129>.foldlstd/core/list/foldl: (xs : list<$2129>, z : $2130, f : ($2130, $2129) -> $2131 $2130) -> $2131 $2130(zz: $2130) fnfn: (x : $2130, y : $2129) -> $2131 $2130(xx: $2130,yy: $2129) ff: ($2129, $2130) -> $2131 $2130(yy: $2129,xx: $2130) + +// Fold a list from the left, i.e. `foldl([1,2],0,(+)) == (0+1)+2` +// Since `foldl` is tail recursive, it is preferred over `foldr` when using an associative function `f` +pub fun foldlstd/core/list/foldl: forall<a,b,e> (xs : list<a>, z : b, f : (b, a) -> e b) -> e b(xsxs: list<$2019> : liststd/core/types/list: V -> V<aa: V>, zz: $2020 : bb: V, ff: ($2020, $2019) -> $2021 $2020 : (bb: V, aa: V) -> ee: E bb: V)result: -> 2054 2053 : ee: E bb: V + match xsxs: list<$2019> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $2019,xxxx: list<$2019>) -> foldlstd/core/list/foldl: (xs : list<$2019>, z : $2020, f : ($2020, $2019) -> $2021 $2020) -> $2021 $2020(xxxx: list<$2019>,ff: ($2020, $2019) -> $2021 $2020(zz: $2020,xx: $2019),ff: ($2020, $2019) -> $2021 $2020) + Nilstd/core/types/Nil: forall<a> list<a> -> zz: $2020 + +pub fun foldl1std/core/list/foldl1: forall<a,e> (xs : list<a>, f : (a, a) -> <exn|e> a) -> <exn|e> a(xsxs: list<$2064> : liststd/core/types/list: V -> V<aa: V>, ff: ($2064, $2064) -> <exn|$2065> $2064 : (aa: V,aa: V) -> <exnstd/core/exn/exn: (E, V) -> V|std/core/types/effect-extend: (X, E) -> Eee: E> aa: V)result: -> <exn|2102> 2101 : <exnstd/core/exn/exn: (E, V) -> V|std/core/types/effect-extend: (X, E) -> Eee: E> aa: V + match xsxs: list<$2064> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $2064,xxxx: list<$2064>) -> xxxx: list<$2064>.foldlstd/core/list/foldl: (xs : list<$2064>, z : $2064, f : ($2064, $2064) -> <exn|$2065> $2064) -> <exn|$2065> $2064(xx: $2064,ff: ($2064, $2064) -> <exn|$2065> $2064) + Nilstd/core/types/Nil: forall<a> list<a> -> throwstd/core/exn/throw: (message : string, info : ? exception-info) -> <exn|$2065> $2064("unexpected Nil in std/core/foldl1"literal: string
count= 33
) + +pub fun foldr1std/core/list/foldr1: forall<a,e> (xs : list<a>, f : (a, a) -> <exn|e> a) -> <exn|e> a(xsxs: list<$2173> : liststd/core/types/list: V -> V<aa: V>, ff: ($2173, $2173) -> <exn|$2174> $2173 : (aa: V,aa: V) -> <exnstd/core/exn/exn: (E, V) -> V|std/core/types/effect-extend: (X, E) -> Eee: E> aa: V)result: -> <exn|2196> 2195 : <exnstd/core/exn/exn: (E, V) -> V|std/core/types/effect-extend: (X, E) -> Eee: E> aa: V + xsxs: list<$2173>.reversestd/core/list/reverse: (xs : list<$2173>) -> <exn|$2174> list<$2173>.foldl1std/core/list/foldl1: (xs : list<$2173>, f : ($2173, $2173) -> <exn|$2174> $2173) -> <exn|$2174> $2173(ff: ($2173, $2173) -> <exn|$2174> $2173) + +// Create a list of `n` repeated elements `x` +pub fun replicatestd/core/list/replicate: forall<a> (x : a, n : int) -> list<a>( xx: $3514 : aa: V, nn: int : intstd/core/types/int: V )result: -> total list<3555> : liststd/core/types/list: V -> V<aa: V> + if nn: int >std/core/int/(>): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
+ then Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $3514, replicatestd/core/list/replicate: (x : $3514, n : int) -> list<$3514>(xx: $3514,pretend-decreasingstd/core/undiv/pretend-decreasing: (x : int) -> int(nn: int.decstd/core/int/dec: (i : int) -> int))) + else Nilstd/core/types/Nil: forall<a> list<a>
+ +// split a list at position `n` +pub fun splitstd/core/list/split: forall<a> (xs : list<a>, n : int) -> (list<a>, list<a>)( xsxs: list<$2617> : liststd/core/types/list: V -> V<aa: V>, nn: int : intstd/core/types/int: V )result: -> total (list<2647>, list<2647>) : (std/core/types/tuple2: (V, V) -> Vliststd/core/types/list: V -> V<aa: V>, liststd/core/types/list: V -> V<aa: V>) + (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)xsxs: list<$2617>.takestd/core/list/take: (xs : list<$2617>, n : int) -> list<$2617>(nn: int), xsxs: list<$2617>.dropstd/core/list/drop: (xs : list<$2617>, n : int) -> list<$2617>(nn: int))std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b) + +pub fun spanstd/core/list/span: forall<a,e> (xs : list<a>, predicate : (a) -> e bool) -> e (list<a>, list<a>)( xsxs: list<$3686> : liststd/core/types/list: V -> V<aa: V>, predicatepredicate: ($3686) -> $3687 bool : aa: V -> ee: E boolstd/core/types/bool: V )result: -> 3763 (list<3762>, list<3762>) : ee: E (std/core/types/tuple2: (V, V) -> Vliststd/core/types/list: V -> V<aa: V>,liststd/core/types/list: V -> V<aa: V>) + // todo: implement TRMC with multiple results to avoid the reverse + fun span-accspan-acc: (ys : list<$3686>, acc : list<$3686>) -> $3687 (list<$3686>, list<$3686>)( ysys: list<$3686>, accacc: list<$3686>)result: -> $3687 (list<$3686>, list<$3686>) + match ysys: list<$3686> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $3686,yyyy: list<$3686>) -> if yy: $3686.predicatepredicate: ($3686) -> $3687 bool then yyyy: list<$3686>.span-accspan-acc: (ys : list<$3686>, acc : list<$3686>) -> $3687 (list<$3686>, list<$3686>)(Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $3686,accacc: list<$3686>)) else (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)accacc: list<$3686>.reversestd/core/list/reverse: (xs : list<$3686>) -> $3687 list<$3686>,ysys: list<$3686>)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b) + _ -> (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)accacc: list<$3686>.reversestd/core/list/reverse: (xs : list<$3686>) -> $3687 list<$3686>, ysys: list<$3686>)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b) + xsxs: list<$3686>.span-accspan-acc: (ys : list<$3686>, acc : list<$3686>) -> $3687 (list<$3686>, list<$3686>)( [std/core/types/Nil: forall<a> list<a>]std/core/types/Nil: forall<a> list<a> ) + +// Keep only those initial elements that satisfy `predicate` +pub fun take-whilestd/core/list/take-while: forall<a,e> (xs : list<a>, predicate : (a) -> e bool) -> e list<a>( xsxs: list<$3791> : liststd/core/types/list: V -> V<aa: V>, predicatepredicate: ($3791) -> $3792 bool : aa: V -> ee: E boolstd/core/types/bool: V )result: -> 3833 list<3832> : ee: E liststd/core/types/list: V -> V<aa: V> + match xsxs: list<$3791> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $3791,xxxx: list<$3791>) -> if xx: $3791.predicatepredicate: ($3791) -> $3792 bool then Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $3791, xxxx: list<$3791>.take-whilestd/core/list/take-while: (xs : list<$3791>, predicate : ($3791) -> $3792 bool) -> $3792 list<$3791>(predicatepredicate: ($3791) -> $3792 bool) ) else Nilstd/core/types/Nil: forall<a> list<a> + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a> + +// Drop all initial elements that satisfy `predicate` +pub fun drop-whilestd/core/list/drop-while: forall<a,e> (xs : list<a>, predicate : (a) -> e bool) -> e list<a>( xsxs: list<$1655> : liststd/core/types/list: V -> V<aa: V>, predicatepredicate: ($1655) -> $1656 bool : aa: V -> ee: E boolstd/core/types/bool: V )result: -> 1688 list<1687> : ee: E liststd/core/types/list: V -> V<aa: V> + match xsxs: list<$1655> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $1655,xxxx: list<$1655>) -> if xx: $1655.predicatepredicate: ($1655) -> $1656 bool then xxxx: list<$1655>.drop-whilestd/core/list/drop-while: (xs : list<$1655>, predicate : ($1655) -> $1656 bool) -> $1656 list<$1655>(predicatepredicate: ($1655) -> $1656 bool) else xsxs: list<$1655> + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a> + +// Retain only those elements of a list that satisfy the given predicate `pred`. +// For example: `filter([1,2,3],odd?) == [1,3]` +pub fun filterstd/core/list/filter: forall<a,e> (xs : list<a>, pred : (a) -> e bool) -> e list<a>( xsxs: list<$1695> : liststd/core/types/list: V -> V<aa: V>, predpred: ($1695) -> $1696 bool : aa: V -> ee: E boolstd/core/types/bool: V )result: -> 1743 list<1742> : ee: E liststd/core/types/list: V -> V<aa: V> + match xsxs: list<$1695> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $1695,xxxx: list<$1695>) -> if predpred: ($1695) -> $1696 bool(xx: $1695) then Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $1695,xxxx: list<$1695>.filterstd/core/list/filter: (xs : list<$1695>, pred : ($1695) -> $1696 bool) -> $1696 list<$1695>(predpred: ($1695) -> $1696 bool)) else xxxx: list<$1695>.filterstd/core/list/filter: (xs : list<$1695>, pred : ($1695) -> $1696 bool) -> $1696 list<$1695>(predpred: ($1695) -> $1696 bool) + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a> + +// Remove those elements of a list that satisfy the given predicate `pred`. +// For example: `remove([1,2,3],odd?) == [2]` +pub fun removestd/core/list/remove: forall<a,e> (xs : list<a>, pred : (a) -> e bool) -> e list<a>( xsxs: list<$3477> : liststd/core/types/list: V -> V<aa: V>, predpred: ($3477) -> $3478 bool : aa: V -> ee: E boolstd/core/types/bool: V )result: -> 3507 list<3506> : ee: E liststd/core/types/list: V -> V<aa: V> + xsxs: list<$3477>.filterstd/core/list/filter: (xs : list<$3477>, pred : ($3477) -> $3478 bool) -> $3478 list<$3477>( fnfn: (x : $3477) -> $3478 bool(xx: $3477) !std/core/types/bool/(!): (b : bool) -> $3478 boolpredpred: ($3477) -> $3478 bool(xx: $3477) ) + +// Partition a list in two lists where the first list contains +// those elements that satisfy the given predicate `pred`. +// For example: `partition([1,2,3],odd?) == ([1,3],[2])` +pub fun partitionstd/core/list/partition: forall<a,e> (xs : list<a>, pred : (a) -> e bool) -> e (list<a>, list<a>)( xsxs: list<$3437> : liststd/core/types/list: V -> V<aa: V>, ^predpred: ($3437) -> $3438 bool : aa: V -> ee: E boolstd/core/types/bool: V )result: -> 3470 (list<3469>, list<3469>) : ee: E (std/core/types/tuple2: (V, V) -> Vliststd/core/types/list: V -> V<aa: V>,liststd/core/types/list: V -> V<aa: V>) + partition-accstd/core/list/partition-acc: (xs : list<$3437>, pred : ($3437) -> $3438 bool, acc1 : ctx<list<$3437>>, acc2 : ctx<list<$3437>>) -> $3438 (list<$3437>, list<$3437>)(xsxs: list<$3437>, predpred: ($3437) -> $3438 bool, ctxctx: ctx<list<$3437>> _hole: list<$3437>, ctxctx: ctx<list<$3437>> _hole: list<$3437>) + +fun partition-accstd/core/list/partition-acc: forall<a,e> (xs : list<a>, pred : (a) -> e bool, acc1 : ctx<list<a>>, acc2 : ctx<list<a>>) -> e (list<a>, list<a>)(xsxs: list<$3293> : liststd/core/types/list: V -> V<aa: V>, ^predpred: ($3293) -> $3294 bool : aa: V -> ee: E boolstd/core/types/bool: V, acc1acc1: ctx<list<$3293>> : ctxstd/core/types/ctx: V -> V<liststd/core/types/list: V -> V<aa: V>>, acc2acc2: ctx<list<$3293>> : ctxstd/core/types/ctx: V -> V<liststd/core/types/list: V -> V<aa: V>>)result: -> 3430 (list<3429>, list<3429>): ee: E (std/core/types/tuple2: (V, V) -> Vliststd/core/types/list: V -> V<aa: V>, liststd/core/types/list: V -> V<aa: V>) + match xsxs: list<$3293> + Nilstd/core/types/Nil: forall<a> list<a> -> (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)acc1acc1: ctx<list<$3293>> ++.std/core/types/cctx/(++.): (c : cctx<list<$3293>,list<$3293>>, x : list<$3293>) -> $3294 list<$3293> Nilstd/core/types/Nil: forall<a> list<a>, acc2acc2: ctx<list<$3293>> ++.std/core/types/cctx/(++.): (c : cctx<list<$3293>,list<$3293>>, x : list<$3293>) -> $3294 list<$3293> Nilstd/core/types/Nil: forall<a> list<a>)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b) + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $3293,xxxx: list<$3293>) -> if predpred: ($3293) -> $3294 bool(xx: $3293) + then partition-accstd/core/list/partition-acc: (xs : list<$3293>, pred : ($3293) -> $3294 bool, acc1 : ctx<list<$3293>>, acc2 : ctx<list<$3293>>) -> $3294 (list<$3293>, list<$3293>)(xxxx: list<$3293>,predpred: ($3293) -> $3294 bool,acc1acc1: ctx<list<$3293>> ++std/core/types/cctx/(++): (c1 : cctx<list<$3293>,list<$3293>>, c2 : cctx<list<$3293>,list<$3293>>) -> $3294 cctx<list<$3293>,list<$3293>> ctxctx: cctx<list<$3293>,list<$3293>> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $3293,_hole: list<$3293>),acc2acc2: ctx<list<$3293>>) + else partition-accstd/core/list/partition-acc: (xs : list<$3293>, pred : ($3293) -> $3294 bool, acc1 : ctx<list<$3293>>, acc2 : ctx<list<$3293>>) -> $3294 (list<$3293>, list<$3293>)(xxxx: list<$3293>,predpred: ($3293) -> $3294 bool,acc1acc1: ctx<list<$3293>>,acc2acc2: ctx<list<$3293>> ++std/core/types/cctx/(++): (c1 : cctx<list<$3293>,list<$3293>>, c2 : cctx<list<$3293>,list<$3293>>) -> $3294 cctx<list<$3293>,list<$3293>> ctxctx: cctx<list<$3293>,list<$3293>> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $3293,_hole: list<$3293>)) + +// Retain only those elements of a list that satisfy the given predicate `pred`. +// For example: `filterMap([1,2,3],fn(i) { if i.odd? then Nothing else Just(i*i) }) == [4]` +pub fun filter-mapstd/core/list/filter-map: forall<a,b,e> (xs : list<a>, pred : (a) -> e maybe<b>) -> e list<b>( xsxs: list<$1750> : liststd/core/types/list: V -> V<aa: V>, predpred: ($1750) -> $1752 maybe<$1751> : aa: V -> ee: E maybestd/core/types/maybe: V -> V<bb: V> )result: -> 1811 list<1810> : ee: E liststd/core/types/list: V -> V<bb: V> + match xsxs: list<$1750> + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $1750,xxxx: list<$1750>) -> match predpred: ($1750) -> $1752 maybe<$1751>(xx: $1750) + Nothingstd/core/types/Nothing: forall<a> maybe<a> -> xxxx: list<$1750>.filter-mapstd/core/list/filter-map: (xs : list<$1750>, pred : ($1750) -> $1752 maybe<$1751>) -> $1752 list<$1751>(predpred: ($1750) -> $1752 maybe<$1751>) + Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(yy: $1751) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $1751,xxxx: list<$1750>.filter-mapstd/core/list/filter-map: (xs : list<$1750>, pred : ($1750) -> $1752 maybe<$1751>) -> $1752 list<$1751>(predpred: ($1750) -> $1752 maybe<$1751>)) + +// Find the first element satisfying some predicate +pub fun findstd/core/list/find: forall<a,e> (xs : list<a>, pred : (a) -> e bool) -> e maybe<a>( xsxs: list<$1872> : liststd/core/types/list: V -> V<aa: V>, predpred: ($1872) -> $1873 bool : aa: V -> ee: E boolstd/core/types/bool: V )result: -> 1907 maybe<1906> : ee: E maybestd/core/types/maybe: V -> V<aa: V> + xsxs: list<$1872>.foreach-whilestd/core/list/foreach-while: (xs : list<$1872>, action : ($1872) -> $1873 maybe<$1872>) -> $1873 maybe<$1872> fnfn: (x : $1872) -> $1873 maybe<$1872>(xx: $1872) + if predpred: ($1872) -> $1873 bool(xx: $1872) then Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: $1872) else Nothingstd/core/types/Nothing: forall<a> maybe<a> + +// Find the first element satisfying some predicate and return it. +pub fun find-maybestd/core/list/find-maybe: forall<a,b,e> (xs : list<a>, pred : (a) -> e maybe<b>) -> e maybe<b>( xsxs: list<$1914> : liststd/core/types/list: V -> V<aa: V>, predpred: ($1914) -> $1916 maybe<$1915> : aa: V -> ee: E maybestd/core/types/maybe: V -> V<bb: V> )result: -> 1938 maybe<1937> : ee: E maybestd/core/types/maybe: V -> V<bb: V> + xsxs: list<$1914>.foreach-whilestd/core/list/foreach-while: (xs : list<$1914>, action : ($1914) -> $1916 maybe<$1915>) -> $1916 maybe<$1915>(predpred: ($1914) -> $1916 maybe<$1915>) + +// Lookup the first element satisfying some predicate +pub fun lookupstd/core/list/lookup: forall<a,b,e> (xs : list<(a, b)>, pred : (a) -> e bool) -> e maybe<b>( xsxs: list<($3052, $3053)> : liststd/core/types/list: V -> V<(std/core/types/tuple2: (V, V) -> Vaa: V,bb: V)>, predpred: ($3052) -> $3054 bool : aa: V -> ee: E boolstd/core/types/bool: V )result: -> 3161 maybe<3160> : ee: E maybestd/core/types/maybe: V -> V<bb: V> + xsxs: list<($3052, $3053)>.foreach-whilestd/core/list/foreach-while: (xs : list<($3052, $3053)>, action : (($3052, $3053)) -> $3054 maybe<$3053>) -> $3054 maybe<$3053> fnfn: (kv : ($3052, $3053)) -> $3054 maybe<$3053>(kvkv: ($3052, $3053)) + if predpred: ($3052) -> $3054 bool(kvkv: ($3052, $3053).fststd/core/types/tuple2/fst: (tuple2 : ($3052, $3053)) -> $3054 $3052) then Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(kvkv: ($3052, $3053).sndstd/core/types/tuple2/snd: (tuple2 : ($3052, $3053)) -> $3054 $3053) else Nothingstd/core/types/Nothing: forall<a> maybe<a> + + +// Convert a `:maybe` type to a list type. +pub fun maybe/liststd/core/list/maybe/list: forall<a> (m : maybe<a>) -> list<a>( mm: maybe<$899> : maybestd/core/types/maybe: V -> V<aa: V> )result: -> total list<924> : liststd/core/types/list: V -> V<aa: V> + match mm: maybe<$899> + Nothingstd/core/types/Nothing: forall<a> maybe<a> -> Nilstd/core/types/Nil: forall<a> list<a> + Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: $899) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $899,Nilstd/core/types/Nil: forall<a> list<a>) + +fun index-of-accstd/core/list/index-of-acc: forall<a,e> (xs : list<a>, pred : (a) -> e bool, idx : int) -> e int( xsxs: list<$2343> : liststd/core/types/list: V -> V<aa: V>, predpred: ($2343) -> $2344 bool : aa: V -> ee: E boolstd/core/types/bool: V, idxidx: int : intstd/core/types/int: V )result: -> 2379 int : ee: E intstd/core/types/int: V + match xsxs: list<$2343> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $2343,xxxx: list<$2343>) -> if predpred: ($2343) -> $2344 bool(xx: $2343) then idxidx: int else index-of-accstd/core/list/index-of-acc: (xs : list<$2343>, pred : ($2343) -> $2344 bool, idx : int) -> $2344 int(xxxx: list<$2343>,predpred: ($2343) -> $2344 bool,idxidx: int+std/core/int/(+): (x : int, y : int) -> $2344 int1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
) + Nilstd/core/types/Nil: forall<a> list<a> -> -1literal: int
dec = -1
hex8 = 0xFF
bit8 = 0b11111111
+ + +// Returns the index of the first element where `pred` holds, or `-1` if no such element exists. +pub fun index-ofstd/core/list/index-of: forall<a,e> (xs : list<a>, pred : (a) -> e bool) -> e int( xsxs: list<$2386> : liststd/core/types/list: V -> V<aa: V>, predpred: ($2386) -> $2387 bool : aa: V -> ee: E boolstd/core/types/bool: V )result: -> 2404 int : ee: E intstd/core/types/int: V + index-of-accstd/core/list/index-of-acc: (xs : list<$2386>, pred : ($2386) -> $2387 bool, idx : int) -> $2387 int( xsxs: list<$2386>, predpred: ($2386) -> $2387 bool, 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) + +// Invoke `action` for each element of a list +pub fun foreachstd/core/list/foreach: forall<a,e> (xs : list<a>, action : (a) -> e ()) -> e ()( xsxs: list<$2203> : liststd/core/types/list: V -> V<aa: V>, actionaction: ($2203) -> $2204 () : (aa: V) -> ee: E (std/core/types/unit: V)std/core/types/unit: V )result: -> 2230 () : ee: E (std/core/types/unit: V)std/core/types/unit: V + match xsxs: list<$2203> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $2203,xxxx: list<$2203>) -> { actionaction: ($2203) -> $2204 ()(xx: $2203); xxxx: list<$2203>.foreachstd/core/list/foreach: (xs : list<$2203>, action : ($2203) -> $2204 ()) -> $2204 ()(actionaction: ($2203) -> $2204 ()) } + Nilstd/core/types/Nil: forall<a> list<a> -> (std/core/types/Unit: ())std/core/types/Unit: () + +// Invoke `action` for each element of a list while `action` return `Nothing` +pub fun foreach-whilestd/core/list/foreach-while: forall<a,b,e> (xs : list<a>, action : (a) -> e maybe<b>) -> e maybe<b>( xsxs: list<$1821> : liststd/core/types/list: V -> V<aa: V>, actionaction: ($1821) -> $1823 maybe<$1822> : (aa: V) -> ee: E maybestd/core/types/maybe: V -> V<bb: V> )result: -> 1862 maybe<1861> : ee: E maybestd/core/types/maybe: V -> V<bb: V> + match xsxs: list<$1821> + Nilstd/core/types/Nil: forall<a> list<a> -> Nothingstd/core/types/Nothing: forall<a> maybe<a> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $1821,xxxx: list<$1821>) -> + match actionaction: ($1821) -> $1823 maybe<$1822>(xx: $1821) + Nothingstd/core/types/Nothing: forall<a> maybe<a> -> xxxx: list<$1821>.foreach-whilestd/core/list/foreach-while: (xs : list<$1821>, action : ($1821) -> $1823 maybe<$1822>) -> $1823 maybe<$1822>(actionaction: ($1821) -> $1823 maybe<$1822>) + justjust: maybe<$1822> -> justjust: maybe<$1822> + +// Invoke `action` on each element of a list while `action` returns `Just` +pub fun map-whilestd/core/list/map-while: forall<a,b,e> (xs : list<a>, action : (a) -> e maybe<b>) -> e list<b>( xsxs: list<$3171> : liststd/core/types/list: V -> V<aa: V>, actionaction: ($3171) -> $3173 maybe<$3172> : (aa: V) -> ee: E maybestd/core/types/maybe: V -> V<bb: V> )result: -> 3223 list<3222> : ee: E liststd/core/types/list: V -> V<bb: V> + match xsxs: list<$3171> + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $3171,xxxx: list<$3171>) -> + match actionaction: ($3171) -> $3173 maybe<$3172>(xx: $3171) + Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(yy: $3172) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $3172,xxxx: list<$3171>.map-whilestd/core/list/map-while: (xs : list<$3171>, action : ($3171) -> $3173 maybe<$3172>) -> $3173 list<$3172>(actionaction: ($3171) -> $3173 maybe<$3172>)) + Nothingstd/core/types/Nothing: forall<a> maybe<a> -> Nilstd/core/types/Nil: forall<a> list<a> + + +// Invoke `action` for each element of a list, passing also the position of the element. +pub fun foreach-indexedstd/core/list/foreach-indexed: forall<a,e> (xs : list<a>, action : (int, a) -> e ()) -> e ()( xsxs: list<$2237> : liststd/core/types/list: V -> V<aa: V>, actionaction: (int, $2237) -> $2238 () : (intstd/core/types/int: V,aa: V) -> ee: E (std/core/types/unit: V)std/core/types/unit: V )result: -> 2336 () : ee: E (std/core/types/unit: V)std/core/types/unit: V + var ii: local-var<$2247,int> := 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
+ xsxs: list<$2237>.foreachstd/core/list/foreach: (xs : list<$2237>, action : ($2237) -> <local<$2247>|$2238> ()) -> <local<$2247>|$2238> () fnfn: (x : $2237) -> <local<$2247>|$2238> ()(xx: $2237) + val jj: int = ii: int // don't dereference `i` inside the inject + mask<local_1: H>{ actionaction: (int, $2237) -> $2238 ()(jj: int,xx: $2237) } + ii: local-var<$2247,int> :=std/core/types/local-set: (v : local-var<$2247,int>, assigned : int) -> <local<$2247>|$2238> () ii: int+std/core/int/(+): (x : int, y : int) -> <local<$2247>|$2238> int
1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
+ +// Insert a separator `sep` between all elements of a list `xs` . +pub fun interspersestd/core/list/intersperse: forall<a> (xs : list<a>, sep : a) -> list<a>( xsxs: list<$777> : liststd/core/types/list: V -> V<aa: V>, sepsep: $777 : aa: V )result: -> total list<836> : liststd/core/types/list: V -> V<aa: V> + fun beforebefore: (ys : list<$777>) -> list<$777>(ysys: list<$777>)result: -> total list<$777> + match ysys: list<$777> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $777,yyyy: list<$777>) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(sepsep: $777,Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $777,beforebefore: (ys : list<$777>) -> list<$777>(yyyy: list<$777>))) + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a> + match xsxs: list<$777> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $777,xxxx: list<$777>) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $777, xxxx: list<$777>.beforebefore: (ys : list<$777>) -> list<$777>) + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a> + +// Concatenate all strings in a list +fun joinsepstd/core/list/joinsep: (xs : list<string>, sep : string) -> string( xsxs: list<string> : liststd/core/types/list: V -> V<stringstd/core/types/string: V>, sepsep: string : stringstd/core/types/string: V )result: -> total string : stringstd/core/types/string: V + fun join-accjoin-acc: (ys : list<string>, acc : string) -> string( ysys: list<string> : liststd/core/types/list: V -> V<stringstd/core/types/string: V>, accacc: string : stringstd/core/types/string: V )result: -> total string : stringstd/core/types/string: V + match ysys: list<string> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: string,yyyy: list<string>) -> join-accjoin-acc: (ys : list<string>, acc : string) -> string(yyyy: list<string>, accacc: string ++std/core/types/(++): (x : string, y : string) -> string sepsep: string ++std/core/types/(++): (x : string, y : string) -> string yy: string) // todo: use string builder + Nilstd/core/types/Nil: forall<a> list<a> -> accacc: string + match xsxs: list<string> + Nilstd/core/types/Nil: forall<a> list<a> -> ""literal: string
count= 0
+ Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: string,xxxx: list<string>) -> join-accjoin-acc: (ys : list<string>, acc : string) -> string(xxxx: list<string>,xx: string
) + +// Concatenate all strings in a list +pub fun joinstd/core/list/join: (xs : list<string>) -> string( xsxs: list<string> : liststd/core/types/list: V -> V<stringstd/core/types/string: V> )result: -> total string : stringstd/core/types/string: V + xsxs: list<string>.joinsepstd/core/list/joinsep: (xs : list<string>, sep : string) -> string(""literal: string
count= 0
) + +// Concatenate all strings in a list using a specific separator +pub fun joinsep/joinstd/core/list/joinsep/join: (xs : list<string>, sep : string) -> string( xsxs: list<string> : liststd/core/types/list: V -> V<stringstd/core/types/string: V>, sepsep: string : stringstd/core/types/string: V )result: -> total string : stringstd/core/types/string: V + xsxs: list<string>.joinsepstd/core/list/joinsep: (xs : list<string>, sep : string) -> string(sepsep: string) + +// Concatenate all strings in a list in reverse order +pub fun reverse-joinstd/core/list/reverse-join: (xs : list<string>) -> string( xsxs: list<string> : liststd/core/types/list: V -> V<stringstd/core/types/string: V> )result: -> total string : stringstd/core/types/string: V + xsxs: list<string>.reversestd/core/list/reverse: (xs : list<string>) -> list<string>.joinsepstd/core/list/joinsep: (xs : list<string>, sep : string) -> string(""literal: string
count= 0
) + +// Append `end` to each string in the list `xs` and join them all together.\ +// `join-end([],end) === ""`\ +// `join-end(["a","b"],"/") === "a/b/"` +pub fun join-endstd/core/list/join-end: (xs : list<string>, end : string) -> string( xsxs: list<string> : liststd/core/types/list: V -> V<stringstd/core/types/string: V>, endend: string : stringstd/core/types/string: V)result: -> total string : stringstd/core/types/string: V + match xsxs: list<string> + Nilstd/core/types/Nil: forall<a> list<a> -> ""literal: string
count= 0
+ _ -> xsxs: list<string>.joinsepstd/core/list/joinsep: (xs : list<string>, sep : string) -> string(endend: string) ++std/core/types/(++): (x : string, y : string) -> string endend: string
+ +// Concatenate all lists in a list (e.g. flatten the list). (tail-recursive) +pub fun concatstd/core/list/concat: forall<a> (xss : list<list<a>>) -> list<a>( xssxss: list<list<$564>> : liststd/core/types/list: V -> V<liststd/core/types/list: V -> V<aa: V>> )result: -> total list<629> : liststd/core/types/list: V -> V<aa: V> + fun concat-preconcat-pre: forall<a> (ys : list<a>, zss : list<list<a>>) -> list<a>( ysys: list<$565> : liststd/core/types/list: V -> V<aa: V>, zsszss: list<list<$565>> : liststd/core/types/list: V -> V<liststd/core/types/list: V -> V<aa: V>> )result: -> total list<610> : liststd/core/types/list: V -> V<aa: V> + match ysys: list<$565> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $565,yyyy: list<$565>) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $565,concat-preconcat-pre: (ys : list<$565>, zss : list<list<$565>>) -> list<$565>(yyyy: list<$565>,zsszss: list<list<$565>>)) + Nilstd/core/types/Nil: forall<a> list<a> -> match zsszss: list<list<$565>> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(zszs: list<$565>,zzszzs: list<list<$565>>) -> concat-preconcat-pre: (ys : list<$565>, zss : list<list<$565>>) -> list<$565>(zszs: list<$565>,zzszzs: list<list<$565>>) + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a> + concat-preconcat-pre: (ys : list<$564>, zss : list<list<$564>>) -> list<$564>([std/core/types/Nil: forall<a> list<a>]std/core/types/Nil: forall<a> list<a>,xssxss: list<list<$564>>) + +// Concatenate the result lists from applying a function to all elements. +pub fun flatmapstd/core/list/flatmap: forall<a,b,e> (xs : list<a>, f : (a) -> e list<b>) -> e list<b>( xsxs: list<$634>: liststd/core/types/list: V -> V<aa: V>, ff: ($634) -> $636 list<$635> : aa: V -> ee: E liststd/core/types/list: V -> V<bb: V> )result: -> 691 list<690> : ee: E liststd/core/types/list: V -> V<bb: V> + fun flatmap-preflatmap-pre: (ys : list<$635>, zs : list<$634>) -> $636 list<$635>( ysys: list<$635>, zszs: list<$634> )result: -> $636 list<$635> + match ysys: list<$635> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $635,yyyy: list<$635>) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $635,flatmap-preflatmap-pre: (ys : list<$635>, zs : list<$634>) -> $636 list<$635>(yyyy: list<$635>,zszs: list<$634>)) + Nilstd/core/types/Nil: forall<a> list<a> -> match zszs: list<$634> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(zz: $634,zzzz: list<$634>) -> flatmap-preflatmap-pre: (ys : list<$635>, zs : list<$634>) -> $636 list<$635>(ff: ($634) -> $636 list<$635>(zz: $634),zzzz: list<$634>) + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a> + flatmap-preflatmap-pre: (ys : list<$635>, zs : list<$634>) -> $636 list<$635>([std/core/types/Nil: forall<a> list<a>]std/core/types/Nil: forall<a> list<a>,xsxs: list<$634>) + +// Concatenate the `Just` result elements from applying a function to all elements. +pub fun flatmap-maybestd/core/list/flatmap-maybe: forall<a,b,e> (xs : list<a>, f : (a) -> e maybe<b>) -> e list<b>( xsxs: list<$1948> : liststd/core/types/list: V -> V<aa: V>, ff: ($1948) -> $1950 maybe<$1949> : aa: V -> ee: E maybestd/core/types/maybe: V -> V<bb: V> )result: -> 2009 list<2008> : ee: E liststd/core/types/list: V -> V<bb: V> + match xsxs: list<$1948> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $1948,xxxx: list<$1948>) -> match ff: ($1948) -> $1950 maybe<$1949>(xx: $1948) + Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(yy: $1949) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $1949, xxxx: list<$1948>.flatmap-maybestd/core/list/flatmap-maybe: (xs : list<$1948>, f : ($1948) -> $1950 maybe<$1949>) -> $1950 list<$1949>(ff: ($1948) -> $1950 maybe<$1949>)) + Nothingstd/core/types/Nothing: forall<a> maybe<a> -> xxxx: list<$1948>.flatmap-maybestd/core/list/flatmap-maybe: (xs : list<$1948>, f : ($1948) -> $1950 maybe<$1949>) -> $1950 list<$1949>(ff: ($1948) -> $1950 maybe<$1949>) + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a> + +// Concatenate a list of `:maybe` values +pub fun concat-maybestd/core/list/concat-maybe: forall<a> (xs : list<maybe<a>>) -> list<a>( xsxs: list<maybe<$1573>> : liststd/core/types/list: V -> V<maybestd/core/types/maybe: V -> V<aa: V>> )result: -> total list<1616> : liststd/core/types/list: V -> V<aa: V> + match xsxs: list<maybe<$1573>> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: maybe<$1573>,xxxx: list<maybe<$1573>>) -> match xx: maybe<$1573> + Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(yy: $1573) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(yy: $1573, xxxx: list<maybe<$1573>>.concat-maybestd/core/list/concat-maybe: (xs : list<maybe<$1573>>) -> list<$1573>) + Nothingstd/core/types/Nothing: forall<a> maybe<a> -> xxxx: list<maybe<$1573>>.concat-maybestd/core/list/concat-maybe: (xs : list<maybe<$1573>>) -> list<$1573> + Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a> + +// Return the last element of a list (or `Nothing` for the empty list) +pub fun laststd/core/list/last: forall<a> (xs : list<a>) -> maybe<a>( xsxs: list<$2536> : liststd/core/types/list: V -> V<aa: V> )result: -> total maybe<2569> : maybestd/core/types/maybe: V -> V<aa: V> + match xsxs: list<$2536> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $2536,Nilstd/core/types/Nil: forall<a> list<a>) -> Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: $2536) + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(_,xxxx: list<$2536>) -> laststd/core/list/last: (xs : list<$2536>) -> maybe<$2536>(xxxx: list<$2536>) + Nilstd/core/types/Nil: forall<a> list<a> -> Nothingstd/core/types/Nothing: forall<a> maybe<a> + +// Return the list without its last element. +// Return an empty list for an empty list. +pub fun initstd/core/list/init: forall<a> (xs : list<a>) -> list<a>( xsxs: list<$2411> : liststd/core/types/list: V -> V<aa: V> )result: -> total list<2441> : liststd/core/types/list: V -> V<aa: V> + match xsxs: list<$2411> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $2411, xxxx: list<$2411> as Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $2411,initstd/core/list/init: (xs : list<$2411>) -> list<$2411>(xxxx: list<$2411>)) + _ -> Nilstd/core/types/Nil: forall<a> list<a> + +// Get (zero-based) element `n` of a list. Return a `:maybe` type. +pub fun @index( xsxs: list<$1367> : liststd/core/types/list: V -> V<aa: V>, nn: int : intstd/core/types/int: V )result: -> total maybe<1426> : maybestd/core/types/maybe: V -> V<aa: V> + match xsxs: list<$1367> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $1367,xxxx: list<$1367>) -> if nn: int>std/core/int/(>): (x : int, y : int) -> bool0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
then xxxx: list<$1367>[nn: int -std/core/int/(-): (x : int, y : int) -> int 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
] // == @index(xx,n-1) + elif nn: int==std/core/int/(==): (x : int, y : int) -> bool0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
then Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: $1367) + else Nothingstd/core/types/Nothing: forall<a> maybe<a> + Nilstd/core/types/Nil: forall<a> list<a> -> Nothingstd/core/types/Nothing: forall<a> maybe<a> + +// Do all elements satisfy a predicate ? +pub fun allstd/core/list/all: forall<a,e> (xs : list<a>, predicate : (a) -> e bool) -> e bool( xsxs: list<$1431> : liststd/core/types/list: V -> V<aa: V>, predicatepredicate: ($1431) -> $1432 bool : aa: V -> ee: E boolstd/core/types/bool: V )result: -> 1462 bool : ee: E boolstd/core/types/bool: V + match xsxs: list<$1431> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $1431,xxxx: list<$1431>) -> if predicatepredicate: ($1431) -> $1432 bool(xx: $1431) then xxxx: list<$1431>.allstd/core/list/all: (xs : list<$1431>, predicate : ($1431) -> $1432 bool) -> $1432 bool(predicatepredicate: ($1431) -> $1432 bool) else Falsestd/core/types/False: bool + Nilstd/core/types/Nil: forall<a> list<a> -> Truestd/core/types/True: bool + +// Are there any elements in a list that satisfy a predicate ? +pub fun anystd/core/list/any: forall<a,e> (xs : list<a>, predicate : (a) -> e bool) -> e bool( xsxs: list<$1469> : liststd/core/types/list: V -> V<aa: V>, predicatepredicate: ($1469) -> $1470 bool : aa: V -> ee: E boolstd/core/types/bool: V )result: -> 1500 bool : ee: E boolstd/core/types/bool: V + match xsxs: list<$1469> + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: $1469,xxxx: list<$1469>) -> if predicatepredicate: ($1469) -> $1470 bool(xx: $1469) then Truestd/core/types/True: bool else xxxx: list<$1469>.anystd/core/list/any: (xs : list<$1469>, predicate : ($1469) -> $1470 bool) -> $1470 bool(predicatepredicate: ($1469) -> $1470 bool) + Nilstd/core/types/Nil: forall<a> list<a> -> Falsestd/core/types/False: bool + +// Return the sum of a list of integers +pub fun sumstd/core/list/sum: (xs : list<int>) -> int( xsxs: list<int> : liststd/core/types/list: V -> V<intstd/core/types/int: V> )result: -> total int : intstd/core/types/int: V + xsxs: list<int>.foldlstd/core/list/foldl: (xs : list<int>, z : int, f : (int, int) -> int) -> int( 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
, fnfn: (x : int, y : int) -> int(xx: int,yy: int) { xx: int +std/core/int/(+): (x : int, y : int) -> int yy: int }
) + +// Returns the smallest element of a list of integers (or `default` (=`0`) for the empty list) +pub fun minimumstd/core/list/minimum: (xs : list<int>, default : ? int) -> int( xsxs: list<int> : liststd/core/types/list: V -> V<intstd/core/types/int: V>, defaultdefault: ? int : intstd/core/types/int: V = 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
)result: -> total int : intstd/core/types/int: V + match xsxs: list<int> + Nilstd/core/types/Nil: forall<a> list<a> -> defaultdefault: int + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: int,xxxx: list<int>) -> xxxx: list<int>.foldlstd/core/list/foldl: (xs : list<int>, z : int, f : (int, int) -> int) -> int( xx: int, minstd/core/int/min: (i : int, j : int) -> int
) + +// Returns the largest element of a list of integers (or `default` (=`0`) for the empty list) +pub fun maximumstd/core/list/maximum: (xs : list<int>, default : ? int) -> int( xsxs: list<int> : liststd/core/types/list: V -> V<intstd/core/types/int: V>, defaultdefault: ? int : intstd/core/types/int: V = 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
)result: -> total int : intstd/core/types/int: V + match xsxs: list<int> + Nilstd/core/types/Nil: forall<a> list<a> -> defaultdefault: int + Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: int,xxxx: list<int>) -> xxxx: list<int>.foldlstd/core/list/foldl: (xs : list<int>, z : int, f : (int, int) -> int) -> int( xx: int, maxstd/core/int/max: (i : int, j : int) -> int
) + + +// Split a string into a list of lines +pub fun linesstd/core/list/lines: (s : string) -> list<string>( ss: string : stringstd/core/types/string: V )result: -> total list<string> : liststd/core/types/list: V -> V<stringstd/core/types/string: V> + ss: string.splitstd/core/string/split: (s : string, sep : string) -> list<string>("\n"literal: string
count= 1
) + +// Join a list of strings with newlines +pub fun unlinesstd/core/list/unlines: (xs : list<string>) -> string( xsxs: list<string> : liststd/core/types/list: V -> V<stringstd/core/types/string: V> )result: -> total string : stringstd/core/types/string: V + xsxs: list<string>.joinstd/core/list/joinsep/join: (xs : list<string>, sep : string) -> string("\n"literal: string
count= 1
) + +// Apply a function `f` to each character in a string +pub fun string/mapstd/core/list/string/map: forall<e> (s : string, f : (char) -> e char) -> e string( ss: string : stringstd/core/types/string: V, ff: (char) -> $2927 char : charstd/core/types/char: V -> ee: E charstd/core/types/char: V )result: -> 2966 string : ee: E stringstd/core/types/string: V + ss: string.liststd/core/string/list: (s : string) -> $2927 list<char>.mapstd/core/list/map: (xs : list<char>, f : (char) -> $2927 char) -> $2927 list<char>(ff: (char) -> $2927 char).stringstd/core/string/listchar/string: (cs : list<char>) -> $2927 string // todo: optimize + +
diff --git a/doc/std_core_list.html b/doc/std_core_list.html index 597d7152f..fc44732b3 100644 --- a/doc/std_core_list.html +++ b/doc/std_core_list.html @@ -15,320 +15,320 @@ -

std/core/list▲toc

+

std/core/list▲toc

-

Standard liststd/core/types/list: V -> V functions. +

Standard liststd/core/types/list: V -> V functions.

.

-
+

Create a list of characters from lo to hi (including hi).

-
fun default/head( xs : liststd/core/types/list: V -> V<a>, default : a ) : a
+
fun default/head( xs : liststd/core/types/list: V -> V<a>, default : a ) : a

Return the head of list with a default value in case the list is empty.

-
+

Applies a function f to list of increasing elements from lo to hi (including both lo and hi ). If lo > hi the function returns the empty list.

-
+

Concatenate all strings in a list using a specific separator.

-
+ -
+

Returns an integer list of increasing elements from lo to hi with stride stride. If lo > hi the function returns the empty list.

-
+

Returns an integer list of increasing elements from lo to hi with stride stride. If lo > hi the function returns the empty list.

-
+

Apply a function f to each character in a string.

-
+ -
+

Element-wise list equality.

-
+

Do all elements satisfy a predicate ?

-
+

Are there any elements in a list that satisfy a predicate ?

-
+ -
+ -
+

Concatenate all lists in a list (e.g. flatten the list). (tail-recursive).

-
+ -
+

Drop the first n elements of a list (or fewer if the list is shorter than n).

-
+

Drop all initial elements that satisfy predicate.

-
+

Retain only those elements of a list that satisfy the given predicate pred. For example: filterstd/core/list/filter: forall<a,e> (xs : list<a>, pred : (a) -> e bool) -> e list<a>([1,2,3],odd?) == [1,3].

-
+

Retain only those elements of a list that satisfy the given predicate pred. -For example: filterMap([1,2,3],fn(i) { if i.odd? then Nothingstd/core/types/Nothing: forall<a> maybe<a> else Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(i(*)std/core/int/(*): (int, int) -> inti) }) == [4]. +For example: filterMap([1,2,3],fn(i) { if i.odd? then Nothingstd/core/types/Nothing: forall<a> maybe<a> else Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(i(*)std/core/int/(*): (int, int) -> inti) }) == [4].

-
+

Find the first element satisfying some predicate.

-
+

Find the first element satisfying some predicate and return it.

-
+

Concatenate the result lists from applying a function to all elements.

-
+
-

Concatenate the Juststd/core/types/Just: forall<a> (value : a) -> maybe<a> result elements from applying a function to all elements. +

Concatenate the Juststd/core/types/Just: forall<a> (value : a) -> maybe<a> result elements from applying a function to all elements.

-
fun foldl( xs : liststd/core/types/list: V -> V<a>, z : b, f : (b, a) -> e b ) : e b
+ - -
fun foldr( xs : liststd/core/types/list: V -> V<a>, z : b, f : (a, b) -> e b ) : e b
+ + - -
fun foreach( xs : liststd/core/types/list: V -> V<a>, action : (a) -> e () ) : e ()
+ +
fun foreach( xs : liststd/core/types/list: V -> V<a>, action : (a) -> e () ) : e ()

Invoke action for each element of a list.

-
fun foreach-indexed( xs : liststd/core/types/list: V -> V<a>, action : (intstd/core/types/int: V, a) -> e () ) : e ()
+
fun foreach-indexed( xs : liststd/core/types/list: V -> V<a>, action : (intstd/core/types/int: V, a) -> e () ) : e ()

Invoke action for each element of a list, passing also the position of the element.

-
+
-

Invoke action for each element of a list while action return Nothingstd/core/types/Nothing: forall<a> maybe<a>. +

Invoke action for each element of a list while action return Nothingstd/core/types/Nothing: forall<a> maybe<a>.

-
std
core
bool
+
bool
-

Standard boolstd/core/types/bool: V functions. +

Standard boolstd/core/types/bool: V functions.

char
+
char
-

Standard charstd/core/types/char: V functions. +

Standard charstd/core/types/char: V functions.

console
+
console

Standard output to the console.

debug
+
debug

Core debugging functions.

delayed
+
delayed

Delayed computations.

either
+
either
exn
+
exn
-

Standard exception (exnstd/core/exn/exn: (E, V) -> V) effect. +

Standard exception (exnstd/core/exn/exn: (E, V) -> V) effect.

hnd
+
hnd

Internal effect handler primitives.

int
+
int
-

Standard integer intstd/core/types/int: V functions. +

Standard integer intstd/core/types/int: V functions.

list
+
list
-

Standard liststd/core/types/list: V -> V functions. +

Standard liststd/core/types/list: V -> V functions.

maybe
+
maybe
-

Standard maybestd/core/types/maybe: V -> V functions. +

Standard maybestd/core/types/maybe: V -> V functions.

order
+
order
-

Standard orderstd/core/types/order: V functions. +

Standard orderstd/core/types/order: V functions.

show
+
show

Standard show functions.

sslice
+
sslice

Efficient views on strings.

string
+
string
-

Standard stringstd/core/types/string: V functions. +

Standard stringstd/core/types/string: V functions.

tuple
+
tuple

Standard tuple functions.

types
+
types

Primitive types and functions.

vector
+
vector

Standard vector functions.