From 3e88cd94c40038f3c09a506623a55dc37a3ce637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Bene=C5=A1?= Date: Fri, 4 Oct 2024 11:39:07 +0200 Subject: [PATCH] Migrate doc comments to use '///' (#628) In preparation for @BinderDavid's #624, I went through the stdlib and tried to change doc comments to use `///` :) --- libraries/common/array.effekt | 70 +-- libraries/common/bench.effekt | 30 +- libraries/common/buffer.effekt | 28 +- libraries/common/bytes.effekt | 20 +- libraries/common/dequeue.effekt | 10 +- libraries/common/effekt.effekt | 36 +- libraries/common/io/console.effekt | 4 +- libraries/common/io/error.effekt | 48 +- libraries/common/io/filesystem.effekt | 34 +- libraries/common/list.effekt | 666 +++++++++++++------------- libraries/common/queue.effekt | 4 +- libraries/common/ref.effekt | 24 +- libraries/common/result.effekt | 20 +- libraries/common/seq.effekt | 77 ++- libraries/common/string.effekt | 22 +- 15 files changed, 479 insertions(+), 614 deletions(-) diff --git a/libraries/common/array.effekt b/libraries/common/array.effekt index 885df441d..6ea066a86 100644 --- a/libraries/common/array.effekt +++ b/libraries/common/array.effekt @@ -4,15 +4,11 @@ import effekt import exception import list -/** - * A mutable 0-indexed fixed-sized array. - */ +/// A mutable 0-indexed fixed-sized array. extern type Array[T] -/** - * Allocates a new array of size `size`, keeping its values _undefined_. - * Prefer using `array` constructor instead to ensure that values are defined. - */ +/// Allocates a new array of size `size`, keeping its values _undefined_. +/// Prefer using `array` constructor instead to ensure that values are defined. extern global def allocate[T](size: Int): Array[T] = js "(new Array(${size}))" chez "(make-vector ${size})" // creates an array filled with 0s on CS @@ -21,9 +17,7 @@ extern global def allocate[T](size: Int): Array[T] = ret %Pos %z """ -/** - * Creates a new Array of size `size` filled with the value `init` - */ +/// Creates a new Array of size `size` filled with the value `init` def array[T](size: Int, init: T): Array[T] = { val arr = allocate[T](size); each(0, size) { i => @@ -32,9 +26,7 @@ def array[T](size: Int, init: T): Array[T] = { arr } -/** - * Converts a List `list` to an Array - */ +/// Converts a List `list` to an Array def fromList[T](list: List[T]): Array[T] = { val listSize = list.size(); val arr = allocate(listSize); @@ -45,9 +37,7 @@ def fromList[T](list: List[T]): Array[T] = { return arr; } -/** - * Gets the length of the array in constant time. - */ +/// Gets the length of the array in constant time. extern pure def size[T](arr: Array[T]): Int = js "${arr}.length" chez "(vector-length ${arr})" @@ -56,12 +46,10 @@ extern pure def size[T](arr: Array[T]): Int = ret %Int %z """ -/** - * Gets the element of the `arr` at given `index` in constant time. - * Unchecked Precondition: `index` is in bounds (0 ≤ index < arr.size) - * - * Prefer using `get` instead. - */ +/// Gets the element of the `arr` at given `index` in constant time. +/// Unchecked Precondition: `index` is in bounds (0 ≤ index < arr.size) +/// +/// Prefer using `get` instead. extern global def unsafeGet[T](arr: Array[T], index: Int): T = js "${arr}[${index}]" chez "(vector-ref ${arr} ${index})" @@ -77,12 +65,10 @@ extern js """ } """ - /** - * Sets the element of the `arr` at given `index` to `value` in constant time. - * Unchecked Precondition: `index` is in bounds (0 ≤ index < arr.size) - * - * Prefer using `set` instead. - */ +/// Sets the element of the `arr` at given `index` to `value` in constant time. +/// Unchecked Precondition: `index` is in bounds (0 ≤ index < arr.size) +/// +/// Prefer using `set` instead. extern global def unsafeSet[T](arr: Array[T], index: Int, value: T): Unit = js "array$set(${arr}, ${index}, ${value})" chez "(begin (vector-set! ${arr} ${index} ${value}) #f)" @@ -91,9 +77,7 @@ extern global def unsafeSet[T](arr: Array[T], index: Int, value: T): Unit = ret %Pos %z """ -/** - * Creates a copy of `arr` - */ +/// Creates a copy of `arr` def copy[T](arr: Array[T]): Array[T] = { with on[OutOfBounds].default { <> }; // should not happen val len = arr.size; @@ -102,10 +86,8 @@ def copy[T](arr: Array[T]): Array[T] = { newArray } -/** - * Copies `length`-many elements from `from` to `to` - * starting at `start` (in `from`) and `offset` (in `to`) - */ +/// Copies `length`-many elements from `from` to `to` +/// starting at `start` (in `from`) and `offset` (in `to`) def copy[T](from: Array[T], start: Int, to: Array[T], offset: Int, length: Int): Unit / Exception[OutOfBounds] = { val startValid = start >= 0 && start + length <= from.size val offsetValid = offset >= 0 && offset + length <= to.size @@ -122,26 +104,20 @@ def copy[T](from: Array[T], start: Int, to: Array[T], offset: Int, length: Int): // Derived operations: -/** - * Gets the element of the `arr` at given `index` in constant time, - * throwing an `Exception[OutOfBounds]` unless `0 ≤ index < arr.size`. - */ +/// Gets the element of the `arr` at given `index` in constant time, +/// throwing an `Exception[OutOfBounds]` unless `0 ≤ index < arr.size`. def get[T](arr: Array[T], index: Int): T / Exception[OutOfBounds] = if (index >= 0 && index < arr.size) arr.unsafeGet(index) else do raise(OutOfBounds(), "Array index out of bounds: " ++ show(index)) -/** - * Sets the element of the `arr` at given `index` to `value` in constant time, - * throwing an `Exception[OutOfBounds]` unless `0 ≤ index < arr.size`. - */ +/// Sets the element of the `arr` at given `index` to `value` in constant time, +/// throwing an `Exception[OutOfBounds]` unless `0 ≤ index < arr.size`. def set[T](arr: Array[T], index: Int, value: T): Unit / Exception[OutOfBounds] = if (index >= 0 && index < arr.size) unsafeSet(arr, index, value) else do raise(OutOfBounds(), "Array index out of bounds: " ++ show(index)) -/** - * Builds a new Array of size `size` from a computation `index` which gets an index - * and returns a value that will be on that position in the resulting array - */ +/// Builds a new Array of size `size` from a computation `index` which gets an index +/// and returns a value that will be on that position in the resulting array def build[T](size: Int) { index: Int => T }: Array[T] = { val arr = allocate[T](size); each(0, size) { i => diff --git a/libraries/common/bench.effekt b/libraries/common/bench.effekt index ae87320ee..f9da062e4 100644 --- a/libraries/common/bench.effekt +++ b/libraries/common/bench.effekt @@ -2,13 +2,11 @@ module bench type Nanos = Int -/** - * The current time (since UNIX Epoch) in nanoseconds. - * - * The actual precision varies across the different backends. - * - js: Milliseconds - * - chez: Microseconds - */ +/// The current time (since UNIX Epoch) in nanoseconds. +/// +/// The actual precision varies across the different backends. +/// - js: Milliseconds +/// - chez: Microseconds extern io def timestamp(): Nanos = js "Date.now() * 1000000" chez "(timestamp)" @@ -32,12 +30,10 @@ extern jsNode """ const { performance } = require('node:perf_hooks'); """ -/** - * High-precision timestamp in nanoseconds that should be for measurements. - * - * This timestamp should only be used for **relative** measurements, - * as gives no guarantees on the absolute time (unlike a UNIX timestamp). - */ +/// High-precision timestamp in nanoseconds that should be for measurements. +/// +/// This timestamp should only be used for **relative** measurements, +/// as gives no guarantees on the absolute time (unlike a UNIX timestamp). extern io def relativeTimestamp(): Nanos = js "Math.round(performance.now() * 1000000)" default { timestamp() } @@ -48,9 +44,7 @@ namespace Duration { def diff(fromNanos: Nanos, toNanos: Nanos): Duration = toNanos - fromNanos } -/** - * Runs the block and returns the time in nanoseconds - */ +/// Runs the block and returns the time in nanoseconds def timed { block: => Unit }: Duration = { val before = relativeTimestamp() block() @@ -70,9 +64,7 @@ def measure(warmup: Int, iterations: Int) { block: => Unit }: Unit = { run(iterations, true) } -/** - * Takes a duration in nanoseconds and formats it in milliseconds with precision of two decimal digits. - */ +/// Takes a duration in nanoseconds and formats it in milliseconds with precision of two decimal digits. def formatMs(nanos: Nanos): String = { val micros = nanos / 1000000 val sub = (nanos.mod(1000000).toDouble / 10000.0).round diff --git a/libraries/common/buffer.effekt b/libraries/common/buffer.effekt index 1b0b638ba..e958897ab 100644 --- a/libraries/common/buffer.effekt +++ b/libraries/common/buffer.effekt @@ -9,34 +9,22 @@ import array record BufferOverflow() -/** - * Fixed-size ring buffers (queues) where one can write - * elements to the head and read from the tail. - */ +/// Fixed-size ring buffers (queues) where one can write +/// elements to the head and read from the tail. interface Buffer[T] { - /** - * The remaining capacity - */ + /// The remaining capacity def capacity(): Int - /** - * Is this buffer full? - */ + /// Is this buffer full? def full?(): Bool - /** - * Is this buffer empty? - */ + /// Is this buffer empty? def empty?(): Bool - /** - * Read an element from the tail of the buffer - */ + /// Read an element from the tail of the buffer def read(): Option[T] - /** - * Write an element to the head of the buffer - */ + /// Write an element to the head of the buffer def write(el: T): Unit / Exception[BufferOverflow] } @@ -120,4 +108,4 @@ namespace examples { println(ringbuffer.read()); println(ringbuffer.read()); } -} \ No newline at end of file +} diff --git a/libraries/common/bytes.effekt b/libraries/common/bytes.effekt index 8f9fbeecb..6cb383e59 100644 --- a/libraries/common/bytes.effekt +++ b/libraries/common/bytes.effekt @@ -1,15 +1,11 @@ module bytes -/** - * A memory managed, mutable, fixed-length buffer of bytes. - */ +/// A memory managed, mutable, fixed-length buffer of bytes. extern type Bytes // = llvm "%Pos" // = js "Uint8Array" -/** - * Allocates new bytes with the given `capacity`, setting its values to `0`. - */ +/// Allocates new bytes with the given `capacity`, setting its values to `0`. extern io def bytes(capacity: Int): Bytes = js "(new Uint8Array(${capacity}))" llvm """ @@ -55,9 +51,7 @@ extern io def write(b: Bytes, index: Int, value: Byte): Unit = ret %Pos zeroinitializer """ -/** - * Returns an *aliased* slice of b starting at offset with the given length - */ +/// Returns an *aliased* slice of b starting at offset with the given length def slice(b: Bytes, offset: Int, length: Int): Bytes = { def validOffset() = offset >= 0 && offset < b.size def validLength() = length >= 0 && (offset + length) <= b.size @@ -66,9 +60,7 @@ def slice(b: Bytes, offset: Int, length: Int): Bytes = { } -/** - * Returns a view into the buffer, with the length truncated to n - */ +/// Returns a view into the buffer, with the length truncated to n def truncated(b: Bytes, n: Int): Bytes = b.slice(0, n) @@ -88,9 +80,7 @@ extern pure def toUTF8(b: Bytes): String = """ namespace unsafe { - /** - * Unsafe: offset and length are not checked. - */ + /// Unsafe: offset and length are not checked. extern io def slice(b: Bytes, offset: Int, length: Int): Bytes = js "new Uint8Array(${b}.buffer, ${offset}, ${length})" llvm """ diff --git a/libraries/common/dequeue.effekt b/libraries/common/dequeue.effekt index bf81d813d..4c3717e89 100644 --- a/libraries/common/dequeue.effekt +++ b/libraries/common/dequeue.effekt @@ -1,11 +1,11 @@ module dequeue -// An implementation of a functional dequeue, using Okasaki's -// bankers dequeue implementation. -// -// Translation from the Haskell implementation: -// https://hackage.haskell.org/package/dequeue-0.1.12/docs/src/Data-Dequeue.html#Dequeue +/// An implementation of a functional dequeue, using Okasaki's +/// bankers dequeue implementation. +/// +/// Translation from the Haskell implementation: +/// https://hackage.haskell.org/package/dequeue-0.1.12/docs/src/Data-Dequeue.html#Dequeue record Dequeue[R](front: List[R], frontSize: Int, rear: List[R], rearSize: Int) def emptyQueue[R](): Dequeue[R] = Dequeue(Nil(), 0, Nil(), 0) diff --git a/libraries/common/effekt.effekt b/libraries/common/effekt.effekt index 56e97e404..2bb048155 100644 --- a/libraries/common/effekt.effekt +++ b/libraries/common/effekt.effekt @@ -144,13 +144,12 @@ extern io def random(): Double = // Equality // ======== -/** - * Result of comparison between two objects according to some order: - * - * - `Less()` means that the first object is *before* the first in the order, - * - `Equal()` means that the two objects are the same in the order, - * - and `Greater()` means that the second object is *before* the first in the order. - */ + +/// Result of comparison between two objects according to some order: +/// +/// - `Less()` means that the first object is *before* the first in the order, +/// - `Equal()` means that the two objects are the same in the order, +/// - and `Greater()` means that the second object is *before* the first in the order. type Ordering { Less(); Equal(); @@ -160,7 +159,8 @@ type Ordering { extern pure def genericCompareImpl[R](x: R, y: R): Int = js "$effekt.compare(${x}, ${y})" - // Compares two values of the same type, returning an `Ordering`. +/// Compares two values of the same type, returning an `Ordering`. +/// Only available on the JavaScript backend. def genericCompare[R](x: R, y: R): Ordering = { genericCompareImpl(x, y) match { case -1 => Less() @@ -182,9 +182,7 @@ def println(o: Ordering): Unit = println(o.show) // Comparison ops // ============== -/** - * Structural equality: Not available in the LLVM backend - */ +/// Structural equality: Not available in the LLVM backend extern pure def equals[R](x: R, y: R): Bool = js "$effekt.equals(${x}, ${y})" chez "(equal? ${x} ${y})" @@ -594,16 +592,12 @@ extern pure def toInt(n: Byte): Int = // chez: #f // llvm: null? -/** - * The value used by the FFI to represent undefined values - */ +/// The value used by the FFI to represent undefined values extern pure def undefined[A](): A = js "undefined" chez "#f" -/** - * Is an FFI value undefined? - */ +/// Is an FFI value undefined? extern pure def isUndefined[A](value: A): Bool = js "(${value} === undefined || ${value} === null)" chez "(eq? ${value} #f)" @@ -638,9 +632,7 @@ def loop { f: {Control} => Unit }: Unit = try { def continue() = loop { f } } -/** - * Calls provided action repeatedly. `start` is inclusive, `end` is not. - */ +/// Calls provided action repeatedly. `start` is inclusive, `end` is not. def each(start: Int, end: Int) { action: (Int) => Unit } = { def loop(i: Int): Unit = if (i < end) { action(i); loop(i + 1) } @@ -648,9 +640,7 @@ def each(start: Int, end: Int) { action: (Int) => Unit } = { loop(start) } -/** - * Calls provided action repeatedly with support for breaking. `start` is inclusive, `end` is not. - */ +/// Calls provided action repeatedly with support for breaking. `start` is inclusive, `end` is not. def each(start: Int, end: Int) { action: (Int) {Control} => Unit } = { var i = start; loop { {l} => diff --git a/libraries/common/io/console.effekt b/libraries/common/io/console.effekt index 12df34974..83f1e173a 100644 --- a/libraries/common/io/console.effekt +++ b/libraries/common/io/console.effekt @@ -7,9 +7,7 @@ interface Console { def writeLine(content: String): Unit } -/** - * Handler for the console effect, using the Console available in js - */ +/// Handler for the console effect, using the Console available in js def console[R] { program: () => R / Console }: R = { val c = js::newConsole() try { diff --git a/libraries/common/io/error.effekt b/libraries/common/io/error.effekt index 7dba331ad..eb25af68f 100644 --- a/libraries/common/io/error.effekt +++ b/libraries/common/io/error.effekt @@ -1,18 +1,16 @@ module io/error -/** - * Errors defined by libuv that can occur in IO operations. - * - * In addition to the named error codes, we also assign each error a - * (positive) integer value that is stable across the different platforms. - * - * For the mapping of IOError and code values, see function fromCode. - * - * While stable, this integer value is supposed to only be used internally. - * All user-facing operations should use values of type IOError, instead. - * - * see: https://docs.libuv.org/en/v1.x/errors.html - */ +/// Errors defined by libuv that can occur in IO operations. +/// +/// In addition to the named error codes, we also assign each error a +/// (positive) integer value that is stable across the different platforms. +/// +/// For the mapping of IOError and code values, see function fromCode. +/// +/// While stable, this integer value is supposed to only be used internally. +/// All user-facing operations should use values of type IOError, instead. +/// +/// see: https://docs.libuv.org/en/v1.x/errors.html type IOError { E2BIG(); EACCES(); @@ -97,11 +95,9 @@ type IOError { EUNATCH() } -/** - * Corresponding error message for a libuv error - * - * see: https://docs.libuv.org/en/v1.x/errors.html - */ +/// Corresponding error message for a libuv error +/// +/// see: https://docs.libuv.org/en/v1.x/errors.html def message(error: IOError): String = error match { case E2BIG() => "argument list too long" case EACCES() => "permission denied" @@ -186,11 +182,9 @@ def message(error: IOError): String = error match { case EUNATCH() => "protocol driver not attached" } -/** - * Corresponding name of a libuv error - * - * see: https://docs.libuv.org/en/v1.x/errors.html - */ +/// Corresponding name of a libuv error +/// +/// see: https://docs.libuv.org/en/v1.x/errors.html def name(error: IOError): String = error match { case E2BIG() => "E2BIG" case EACCES() => "EACCES" @@ -275,11 +269,9 @@ def name(error: IOError): String = error match { case EUNATCH() => "EUNATCH" } -/** - * Translates a integer code value to an IOError. - * - * See documentation of type IOError for further information. - */ +/// Translates a integer code value to an IOError. +/// +/// See documentation of type IOError for further information. def fromNumber(number: Int): IOError = number match { case 1 => EPERM() case 2 => ENOENT() diff --git a/libraries/common/io/filesystem.effekt b/libraries/common/io/filesystem.effekt index 56e7fee34..66fd2f8ef 100644 --- a/libraries/common/io/filesystem.effekt +++ b/libraries/common/io/filesystem.effekt @@ -6,10 +6,8 @@ import io import io/error -/** - * Represents the file opening modes with their respective flags - * Backends rely on the order of these - */ +/// Represents the file opening modes with their respective flags +/// Backends rely on the order of these type Mode { // Most common modes ReadOnly() // 'r' exception if does not exist @@ -30,15 +28,11 @@ type Mode { } -/** - * A file descriptor. Should not be inspected. - */ +/// A file descriptor. Should not be inspected. type File = Int -/** - * Reads a file at given path as utf8 encoded string. - */ +/// Reads a file at given path as utf8 encoded string. def readFile(path: String): String / Exception[IOError] = { val fd = open(path, ReadOnly()); with on[IOError].finalize { close(fd) } @@ -71,9 +65,7 @@ def readFile(path: String): String / Exception[IOError] = { go() } -/** - * Writes the (utf8 encoded) string `contents` into the specified file. - */ +/// Writes the (utf8 encoded) string `contents` into the specified file. def writeFile(path: String, contents: String): Unit / Exception[IOError] = { val fd = open(path, WriteOnly()); with on[IOError].finalize { close(fd) } @@ -100,21 +92,17 @@ def writeFile(path: String, contents: String): Unit / Exception[IOError] = { } -/** - * An abstract interface applications can program against. - * - * Can be interpreted with the `filesystem` handler, or virtualized etc. - * - * See example below. - */ +/// An abstract interface applications can program against. +/// +/// Can be interpreted with the `filesystem` handler, or virtualized etc. +/// +/// See example below. interface Files { def readFile(path: String): String def writeFile(path: String, contents: String): Unit } -/** - * Using the file system via node.js - */ +/// Using the file system via node.js def filesystem[R] { program: => R / Files }: R / Exception[IOError] = // TODO move Exception to be bidirectional try { program() } with Files { diff --git a/libraries/common/list.effekt b/libraries/common/list.effekt index 4d08a307b..d2c8b05ee 100644 --- a/libraries/common/list.effekt +++ b/libraries/common/list.effekt @@ -4,32 +4,32 @@ import effekt import option import exception -// Immutable linked list for finite sequences of elements. +/// Immutable linked list for finite sequences of elements. type List[A] { Nil(); Cons(head: A, tail: List[A]) } -// Create an empty list. -// -// O(1) +/// Create an empty list. +/// +/// O(1) def empty[A](): List[A] = Nil() -// Create a list with one element. -// -// O(1) +/// Create a list with one element. +/// +/// O(1) def singleton[A](x: A): List[A] = Cons(x, Nil()) -// Create a list of length `size` where all elements are `default`. -// -// O(size) +/// Create a list of length `size` where all elements are `default`. +/// +/// O(size) def fill[A](size: Int, default: A): List[A] = { build(size) { i => default } } -// Create a list from a function `index` of given `size`. -// -// O(size) +/// Create a list from a function `index` of given `size`. +/// +/// O(size) def build[A](size: Int) { index: Int => A }: List[A] = { var result = empty() each(0, size) { i => @@ -38,52 +38,52 @@ def build[A](size: Int) { index: Int => A }: List[A] = { result.reverse } -// Check if list is empty. -// -// O(1) +/// Check if list is empty. +/// +/// O(1) def isEmpty[A](l: List[A]): Bool = l match { case Nil() => true case Cons(a, rest) => false } -// Check if list is nonempty. -// -// O(1) +/// Check if list is nonempty. +/// +/// O(1) def nonEmpty[A](l: List[A]): Bool = l match { case Nil() => false case Cons(a, rest) => true } -// Return the first element of a given list. -// Throws a `MissingValue` exception if it's empty. -// -// O(1) +/// Return the first element of a given list. +/// Throws a `MissingValue` exception if it's empty. +/// +/// O(1) def head[A](l: List[A]): A / Exception[MissingValue] = l match { case Nil() => do raise(MissingValue(), "Trying to get the head of an empty list") case Cons(a, rest) => a } -// Return all elements of a given list except the first element. -// Throws a `MissingValue` exception if it's empty. -// -// O(1) +/// Return all elements of a given list except the first element. +/// Throws a `MissingValue` exception if it's empty. +/// +/// O(1) def tail[A](l: List[A]): List[A] / Exception[MissingValue] = l match { case Nil() => do raise(MissingValue(), "Trying to get the head of an empty list") case Cons(a, rest) => rest } -// Return the first element of a given list. -// Returns `None()` if it's empty. -// -// O(1) +/// Return the first element of a given list. +/// Returns `None()` if it's empty. +/// +/// O(1) def headOption[A](l: List[A]): Option[A] = l match { case Nil() => None() case Cons(a, rest) => Some(a) } -// Returns the last element of a given list. -// -// O(N) +/// Returns the last element of a given list. +/// +/// O(N) def last[A](l: List[A]): A / Exception[MissingValue] = { def go(list: List[A]): A = { list match { @@ -96,9 +96,9 @@ def last[A](l: List[A]): A / Exception[MissingValue] = { go(l) } -// Get the value at given index. -// -// O(N) +/// Get the value at given index. +/// +/// O(N) def get[A](list: List[A], index: Int): A / Exception[OutOfBounds] = { def go(list: List[A], i: Int): A = { list match { @@ -111,17 +111,17 @@ def get[A](list: List[A], index: Int): A / Exception[OutOfBounds] = { go(list, index) } -// Traverse a list, applying the given action on every element. -// -// O(N) +/// Traverse a list, applying the given action on every element. +/// +/// O(N) def foreach[A](l: List[A]) { f: (A) => Unit } : Unit = l match { case Nil() => () case Cons(head, tail) => f(head); tail.foreach {f} } -// Traverse a list, applying the given action on every element. -// -// O(N) +/// Traverse a list, applying the given action on every element. +/// +/// O(N) def foreach[A](l: List[A]) { f: (A) {Control} => Unit } : Unit = { var remainder = l loop { {label} => @@ -134,9 +134,9 @@ def foreach[A](l: List[A]) { f: (A) {Control} => Unit } : Unit = { } } -// Traverse a list, applying the given action on every element and its (zero-based) index. -// -// O(N) +/// Traverse a list, applying the given action on every element and its (zero-based) index. +/// +/// O(N) def foreachIndex[A](list: List[A]){ f: (Int, A) => Unit }: Unit = { def loop(index: Int, remainder: List[A]): Unit = remainder match { case Nil() => () @@ -147,9 +147,9 @@ def foreachIndex[A](list: List[A]){ f: (Int, A) => Unit }: Unit = { loop(0, list) } -// Traverse a list, applying the given action on every element and its (zero-based) index. -// -// O(N) +/// Traverse a list, applying the given action on every element and its (zero-based) index. +/// +/// O(N) def foreachIndex[A](list: List[A]){ f: (Int, A) {Control} => Unit }: Unit = { var remainder = list var i = -1 @@ -164,20 +164,20 @@ def foreachIndex[A](list: List[A]){ f: (Int, A) {Control} => Unit }: Unit = { } } -// Map a function `f` over elements in a given list. -// -// O(N) +/// Map a function `f` over elements in a given list. +/// +/// O(N) def map[A, B](l: List[A]) { f: A => B } : List[B] = { var acc = Nil[B]() l.foreach { el => acc = Cons(f(el), acc) } acc.reverse } -// Map a function `f` over elements in a given list, -// keeping only the elements for which the function returned `Some(...)`, -// discarding the elements for which the function returned `None()`. -// -// O(N) +/// Map a function `f` over elements in a given list, +/// keeping only the elements for which the function returned `Some(...)`, +/// discarding the elements for which the function returned `None()`. +/// +/// O(N) def collect[A, B](l: List[A]) { f : A => Option[B] }: List[B] = { var acc = Nil[B]() l.foreach { a => @@ -190,9 +190,9 @@ def collect[A, B](l: List[A]) { f : A => Option[B] }: List[B] = { acc.reverse } -// Map a function `f` over elements in a given list and concatenate the results. -// -// O(N) +/// Map a function `f` over elements in a given list and concatenate the results. +/// +/// O(N) def flatMap[A, B](l: List[A]) { f : A => List[B] }: List[B] = { var acc = Nil[B]() l.foreach { a => @@ -202,9 +202,9 @@ def flatMap[A, B](l: List[A]) { f : A => List[B] }: List[B] = { acc } -// Check if predicate is true for all elements of the given list. -// -// O(N) +/// Check if predicate is true for all elements of the given list. +/// +/// O(N) def all[A](list: List[A]) { predicate: A => Bool }: Bool = { list match { case Cons(x, xs) => predicate(x) && all(xs) { predicate } @@ -212,9 +212,9 @@ def all[A](list: List[A]) { predicate: A => Bool }: Bool = { } } -// Check if predicate is true for at least one element of the given list. -// -// O(N) +/// Check if predicate is true for at least one element of the given list. +/// +/// O(N) def any[A](list: List[A]) { predicate: A => Bool }: Bool = { list match { case Cons(x, xs) => predicate(x) || any(xs) { predicate } @@ -222,89 +222,89 @@ def any[A](list: List[A]) { predicate: A => Bool }: Bool = { } } -// Fold a list using `f`, starting from the left given a starting value. -// -// O(N) +/// Fold a list using `f`, starting from the left given a starting value. +/// +/// O(N) def foldLeft[A, B](l: List[A], init: B) { f: (B, A) => B }: B = { var acc = init; l.foreach { x => acc = f(acc, x) }; acc } -// Fold a list using `f`, starting from the right given a starting value. -// -// O(N) +/// Fold a list using `f`, starting from the right given a starting value. +/// +/// O(N) def foldRight[A, B](l: List[A], init: B) { f: (A, B) => B }: B = { var acc = init; l.reverse.foreach { x => acc = f(x, acc) }; acc } -// Sum the elements of the list. -// -// O(N) +/// Sum the elements of the list. +/// +/// O(N) def sum(list: List[Int]): Int = { var n = 0; list.foreach { x => n = n + x }; n } -// Calculate the size of the list. -// -// O(N) +/// Calculate the size of the list. +/// +/// O(N) def size[A](l: List[A]): Int = { var n = 0; l.foreach { _ => n = n + 1 }; n } -// Reverse the list. -// -// O(N) +/// Reverse the list. +/// +/// O(N) def reverse[A](l: List[A]): List[A] = { var res = Nil[A]() l.foreach { el => res = Cons(el, res) } res } -// Reverse a list `l` and append `other` to it. -// -// Example: -// ``` -// > [1,2,3].reverseOnto([4,5,6]) -// [3,2,1,4,5,6] -// ``` -// -// O(|l|) +/// Reverse a list `l` and append `other` to it. +/// +/// Example: +/// ``` +/// > [1,2,3].reverseOnto([4,5,6]) +/// [3,2,1,4,5,6] +/// ``` +/// +/// O(|l|) def reverseOnto[A](l: List[A], other: List[A]): List[A] = l match { case Nil() => other case Cons(a, rest) => rest.reverseOnto(Cons(a, other)) } -// Concatenate list `l` with list `other`: -// -// Example: -// ``` -// > [1,2,3].append([4,5,6]) -// [1,2,3,4,5,6] -// ``` -// -// O(N) +/// Concatenate list `l` with list `other`: +/// +/// Example: +/// ``` +/// > [1,2,3].append([4,5,6]) +/// [1,2,3,4,5,6] +/// ``` +/// +/// O(N) def append[A](l: List[A], other: List[A]): List[A] = l.reverse.reverseOnto(other) -// Flatten a list of lists into a single list. -// -// Examples: -// ``` -// > [[1, 2, 3], [4, 5], [6]].join() -// [1, 2, 3, 4, 5, 6] -// -// > [[]].join() -// [] -// ``` -// -// O(N) +/// Flatten a list of lists into a single list. +/// +/// Examples: +/// ``` +/// > [[1, 2, 3], [4, 5], [6]].join() +/// [1, 2, 3, 4, 5, 6] +/// +/// > [[]].join() +/// [] +/// ``` +/// +/// O(N) def join[A](lists: List[List[A]]): List[A] = { var acc: List[A] = Nil() lists.foreach { list => @@ -313,19 +313,19 @@ def join[A](lists: List[List[A]]): List[A] = { acc } -// Flatten a list of lists into a single list, -// putting the `between` list in between each list in the input. -// -// Examples: -// ``` -// > [[100], [200, 300], [400]].join([1, 2, 3]) -// [100, 1, 2, 3, 200, 300, 1, 2, 3, 400] -// -// > [[]].join([1, 2, 3]) -// [] -// ``` -// -// O(N) +/// Flatten a list of lists into a single list, +/// putting the `between` list in between each list in the input. +/// +/// Examples: +/// ``` +/// > [[100], [200, 300], [400]].join([1, 2, 3]) +/// [100, 1, 2, 3, 200, 300, 1, 2, 3, 400] +/// +/// > [[]].join([1, 2, 3]) +/// [] +/// ``` +/// +/// O(N) def join[A](lists: List[List[A]], between: List[A]): List[A] = { lists match { case Nil() => Nil() @@ -336,27 +336,27 @@ def join[A](lists: List[List[A]], between: List[A]): List[A] = { } } -// Take the first `n` elements of a given list. -// -// Examples: -// ``` -// > [1, 2, 3].take(2) -// [1, 2] -// -// > [1, 2, 3].take(0) -// [] -// -// > [1, 2, 3].take(3) -// [1, 2, 3] -// -// > [1, 2, 3].take(5) -// [1, 2, 3] -// -// > [1, 2, 3].take(-1) -// [] -// ``` -// -// O(n) +/// Take the first `n` elements of a given list. +/// +/// Examples: +/// ``` +/// > [1, 2, 3].take(2) +/// [1, 2] +/// +/// > [1, 2, 3].take(0) +/// [] +/// +/// > [1, 2, 3].take(3) +/// [1, 2, 3] +/// +/// > [1, 2, 3].take(5) +/// [1, 2, 3] +/// +/// > [1, 2, 3].take(-1) +/// [] +/// ``` +/// +/// O(n) def take[A](l: List[A], n: Int): List[A] = if (n <= 0) { Nil() @@ -365,27 +365,27 @@ def take[A](l: List[A], n: Int): List[A] = case Cons(a, rest) => Cons(a, rest.take(n - 1)) } -// Drop the first `n` elements of a given list. -// -// Examples: -// ``` -// > [1, 2, 3].drop(2) -// [3] -// -// > [1, 2, 3].drop(0) -// [1, 2, 3] -// -// > [1, 2, 3].drop(3) -// [] -// -// > [1, 2, 3].drop(5) -// [] -// -// > [1, 2, 3].drop(-1) -// [1, 2, 3] -// ``` -// -// O(n) +/// Drop the first `n` elements of a given list. +/// +/// Examples: +/// ``` +/// > [1, 2, 3].drop(2) +/// [3] +/// +/// > [1, 2, 3].drop(0) +/// [1, 2, 3] +/// +/// > [1, 2, 3].drop(3) +/// [] +/// +/// > [1, 2, 3].drop(5) +/// [] +/// +/// > [1, 2, 3].drop(-1) +/// [1, 2, 3] +/// ``` +/// +/// O(n) def drop[A](l: List[A], n: Int): List[A] = if (n <= 0) { l @@ -394,57 +394,57 @@ def drop[A](l: List[A], n: Int): List[A] = case Cons(a, rest) => rest.drop(n - 1) } -// Return a slice of a given list from the starting index (inclusive) -// to the given end index (exclusive). -// -// Examples: -// ``` -// > [1, 2, 3, 4, 5, 6].slice(1, 4) -// [2, 3, 4] -// -// > [1, 2, 3, 4, 5, 6].slice(1, 2) -// [2] -// -// > [1, 2, 3, 4, 5, 6].slice(1, 1) -// [] -// -// > [1, 2, 3, 4, 5, 6].slice(4, 1) -// [] -// -// > [1, 2, 3, 4, 5, 6].slice(-100, 100) -// [1, 2, 3, 4, 5, 6] -// ``` -// -// O(N) +/// Return a slice of a given list from the starting index (inclusive) +/// to the given end index (exclusive). +/// +/// Examples: +/// ``` +/// > [1, 2, 3, 4, 5, 6].slice(1, 4) +/// [2, 3, 4] +/// +/// > [1, 2, 3, 4, 5, 6].slice(1, 2) +/// [2] +/// +/// > [1, 2, 3, 4, 5, 6].slice(1, 1) +/// [] +/// +/// > [1, 2, 3, 4, 5, 6].slice(4, 1) +/// [] +/// +/// > [1, 2, 3, 4, 5, 6].slice(-100, 100) +/// [1, 2, 3, 4, 5, 6] +/// ``` +/// +/// O(N) def slice[A](list: List[A], start: Int, stopExclusive: Int): List[A] = { val prefix = list.drop(start) val length = stopExclusive - start prefix.take(length) } -// Split the list at given index. -// -// Law: `val (l, r) = list.splitAt(i); l.append(r) === list` -// -// O(N) +/// Split the list at given index. +/// +/// Law: `val (l, r) = list.splitAt(i); l.append(r) === list` +/// +/// O(N) def splitAt[A](list: List[A], index: Int): (List[A], List[A]) = { (list.take(index), list.drop(index)) } -// Update the element at given index in the list using the `update` function. -// Returns the original list if the index is out of bounds. -// -// See: `modifyAt` -// Examples: -// ``` -// > [1, 2, 3].updateAt(1) { n => n + 100 } -// [1, 102, 3] -// -// > [1, 2, 3].updateAt(10) { n => n + 100 } -// [1, 2, 3] -// ``` -// -// O(N) +/// Update the element at given index in the list using the `update` function. +/// Returns the original list if the index is out of bounds. +/// +/// See: `modifyAt` +/// Examples: +/// ``` +/// > [1, 2, 3].updateAt(1) { n => n + 100 } +/// [1, 102, 3] +/// +/// > [1, 2, 3].updateAt(10) { n => n + 100 } +/// [1, 2, 3] +/// ``` +/// +/// O(N) def updateAt[A](list: List[A], index: Int) { update: A => A }: List[A] = { list.splitAt(index) match { case (left, Cons(x, right)) => @@ -453,20 +453,20 @@ def updateAt[A](list: List[A], index: Int) { update: A => A }: List[A] = { } } -// Modify the element at given index in the list using the `update` function. -// Throws `OutOfBounds` if the index is out of bounds. -// -// See: `updateAt` -// Examples: -// ``` -// > [1, 2, 3].modifyAt(1) { n => n + 100 } -// Some([1, 102, 3]) -// -// > [1, 2, 3].modifyAt(10) { n => n + 100 } -// None() -// ``` -// -// O(N) +/// Modify the element at given index in the list using the `update` function. +/// Throws `OutOfBounds` if the index is out of bounds. +/// +/// See: `updateAt` +/// Examples: +/// ``` +/// > [1, 2, 3].modifyAt(1) { n => n + 100 } +/// Some([1, 102, 3]) +/// +/// > [1, 2, 3].modifyAt(10) { n => n + 100 } +/// None() +/// ``` +/// +/// O(N) def modifyAt[A](list: List[A], index: Int) { update: A => A }: List[A] / Exception[OutOfBounds] = { list.splitAt(index) match { case (left, Cons(x, right)) => @@ -475,69 +475,69 @@ def modifyAt[A](list: List[A], index: Int) { update: A => A }: List[A] / Excepti } } -// Delete the element at given index in the list. -// -// Example: -// ``` -// > [1, 2, 3, 4].deleteAt(1) -// [1, 3, 4] -// -// > [1, 2, 3, 4].deleteAt(-1) -// [1, 2, 3, 4] -// -// > [1, 2, 3, 4].deleteAt(10) -// [1, 2, 3, 4] -// ``` -// -// O(N) +/// Delete the element at given index in the list. +/// +/// Example: +/// ``` +/// > [1, 2, 3, 4].deleteAt(1) +/// [1, 3, 4] +/// +/// > [1, 2, 3, 4].deleteAt(-1) +/// [1, 2, 3, 4] +/// +/// > [1, 2, 3, 4].deleteAt(10) +/// [1, 2, 3, 4] +/// ``` +/// +/// O(N) def deleteAt[A](list: List[A], index: Int): List[A] = { val left = list.slice(0, index) val right = list.slice(index + 1, list.size()) left.append(right) } -// Add an element at given index in the list. -// -// Examples: -// ``` -// > [1, 2, 3].insert(-1, 0) -// [0, 1, 2, 3] -// -// > [1, 2, 3].insert(0, 0) -// [0, 1, 2, 3] -// -// > [1, 2, 3].insert(1, 0) -// [1, 0, 2, 3] -// -// > [1, 2, 3].insert(3, 0) -// [1, 2, 3, 0] -// -// > [1, 2, 3].insert(10, 0) -// [1, 2, 3, 0] -// ``` -// -// O(N) +/// Add an element at given index in the list. +/// +/// Examples: +/// ``` +/// > [1, 2, 3].insert(-1, 0) +/// [0, 1, 2, 3] +/// +/// > [1, 2, 3].insert(0, 0) +/// [0, 1, 2, 3] +/// +/// > [1, 2, 3].insert(1, 0) +/// [1, 0, 2, 3] +/// +/// > [1, 2, 3].insert(3, 0) +/// [1, 2, 3, 0] +/// +/// > [1, 2, 3].insert(10, 0) +/// [1, 2, 3, 0] +/// ``` +/// +/// O(N) def insert[A](list: List[A], index: Int, x: A): List[A] = { val (left, right) = list.splitAt(index) left.append(Cons(x, right)) } -// Replace an element at given index in the list. -// Returns the original list when the index is out of bounds. -// -// Examples: -// ``` -// > [1, 2, 3].replace(0, 42) -// [42, 2, 3] -// -// > [1, 2, 3].replace(-1, 42) -// [1, 2, 3] -// -// > [1, 2, 3].replace(10, 42) -// [1, 2, 3] -// ``` -// -// O(N) +/// Replace an element at given index in the list. +/// Returns the original list when the index is out of bounds. +/// +/// Examples: +/// ``` +/// > [1, 2, 3].replace(0, 42) +/// [42, 2, 3] +/// +/// > [1, 2, 3].replace(-1, 42) +/// [1, 2, 3] +/// +/// > [1, 2, 3].replace(10, 42) +/// [1, 2, 3] +/// ``` +/// +/// O(N) def replace[A](list: List[A], index: Int, x: A): List[A] = { if (index < 0 || index >= list.size()) { list @@ -548,25 +548,25 @@ def replace[A](list: List[A], index: Int, x: A): List[A] = { } } -// Produce a list of pairs from a pair of lists. -// The length of the result is the minimum of lengths of the two lists. -// -// Examples: -// ``` -// > zip([1, 2, 3], [100, 200, 300]) -// [(1, 100), (2, 200), (3, 300)] -// -// > zip([1, 2, 3], Nil[Int]()) -// [] -// -// > zip(Nil[Int](), [1, 2, 3]) -// [] -// -// > zip([1, 2, 3], [42]) -// [(1, 42)] -// ``` -// -// O(N) +/// Produce a list of pairs from a pair of lists. +/// The length of the result is the minimum of lengths of the two lists. +/// +/// Examples: +/// ``` +/// > zip([1, 2, 3], [100, 200, 300]) +/// [(1, 100), (2, 200), (3, 300)] +/// +/// > zip([1, 2, 3], Nil[Int]()) +/// [] +/// +/// > zip(Nil[Int](), [1, 2, 3]) +/// [] +/// +/// > zip([1, 2, 3], [42]) +/// [(1, 42)] +/// ``` +/// +/// O(N) def zip[A, B](left: List[A], right: List[B]): List[(A, B)] = { def go(acc: List[(A, B)], left: List[A], right: List[B]): List[(A, B)] = { (left, right) match { @@ -580,25 +580,25 @@ def zip[A, B](left: List[A], right: List[B]): List[(A, B)] = { go(Nil(), left, right) } -// Combine two lists with the given function. -// The length of the result is the minimum of lengths of the two lists. -// -// Examples: -// ``` -// > zipWith([1, 2, 3], [100, 200, 300]) { (a, b) => a + b } -// [101, 202, 303] -// -// > zipWith([1, 2, 3], Nil[Int]()) { (a, b) => a + b } -// [] -// -// > zipWith(Nil[Int](), [1, 2, 3]) { (a, b) => a + b } -// [] -// -// > zipWith([1, 2, 3], [42]) { (a, b) => a + b } -// [43] -// ``` -// -// O(N) +/// Combine two lists with the given function. +/// The length of the result is the minimum of lengths of the two lists. +/// +/// Examples: +/// ``` +/// > zipWith([1, 2, 3], [100, 200, 300]) { (a, b) => a + b } +/// [101, 202, 303] +/// +/// > zipWith([1, 2, 3], Nil[Int]()) { (a, b) => a + b } +/// [] +/// +/// > zipWith(Nil[Int](), [1, 2, 3]) { (a, b) => a + b } +/// [] +/// +/// > zipWith([1, 2, 3], [42]) { (a, b) => a + b } +/// [43] +/// ``` +/// +/// O(N) def zipWith[A, B, C](left: List[A], right: List[B]) { combine : (A, B) => C }: List[C] = { def go(acc: List[C], left: List[A], right: List[B]): List[C] = { (left, right) match { @@ -612,15 +612,15 @@ def zipWith[A, B, C](left: List[A], right: List[B]) { combine : (A, B) => C }: L go(Nil(), left, right) } -// Produce a pair of lists from a list of pairs. -// -// Examples: -// ``` -// > [(1, 100), (2, 200), (3, 300)].unzip() -// ([1, 2, 3], [100, 200, 300]) -// ``` -// -// O(N) +/// Produce a pair of lists from a list of pairs. +/// +/// Examples: +/// ``` +/// > [(1, 100), (2, 200), (3, 300)].unzip() +/// ([1, 2, 3], [100, 200, 300]) +/// ``` +/// +/// O(N) def unzip[A, B](pairs: List[(A, B)]): (List[A], List[B]) = { pairs match { case Nil() => (Nil(), Nil()) @@ -630,11 +630,11 @@ def unzip[A, B](pairs: List[(A, B)]): (List[A], List[B]) = { } } -// Partition a given list into two lists. -// The left list contains the elements that satsify the predicate, -// the right list contains the elements that do not. -// -// O(N) +/// Partition a given list into two lists. +/// The left list contains the elements that satsify the predicate, +/// the right list contains the elements that do not. +/// +/// O(N) def partition[A](l: List[A]) { pred: A => Bool }: (List[A], List[A]) = { var lefts: List[A] = Nil() var rights: List[A] = Nil() @@ -649,11 +649,11 @@ def partition[A](l: List[A]) { pred: A => Bool }: (List[A], List[A]) = { (lefts.reverse, rights.reverse) } -// Sort a list using a given comparison function. -// -// Note: this implementation is not stacksafe! -// -// O(N log N) +/// Sort a list using a given comparison function. +/// +/// Note: this implementation is not stacksafe! +/// +/// O(N log N) def sortBy[A](l: List[A]) { compare: (A, A) => Bool }: List[A] = l match { case Nil() => Nil() @@ -667,9 +667,9 @@ def sortBy[A](l: List[A]) { compare: (A, A) => Bool }: List[A] = def sort(l: List[Int]): List[Int] = l.sortBy { (a, b) => a < b } def sort(l: List[Double]): List[Double] = l.sortBy { (a, b) => a < b } -// Check if a list is sorted according to the given comparison function. -// -// O(N) +/// Check if a list is sorted according to the given comparison function. +/// +/// O(N) def isSortedBy[A](list: List[A]) { compare: (A, A) => Bool }: Bool = { def go(list: List[A]): Bool = { list match { diff --git a/libraries/common/queue.effekt b/libraries/common/queue.effekt index 10b453f8d..d01c28640 100644 --- a/libraries/common/queue.effekt +++ b/libraries/common/queue.effekt @@ -2,9 +2,7 @@ module queue import array -/** - * Mutable, automatically resizing queue. - */ +/// Mutable, automatically resizing queue. interface Queue[T] { def empty?(): Bool diff --git a/libraries/common/ref.effekt b/libraries/common/ref.effekt index 7c61a36b5..f02d1214c 100644 --- a/libraries/common/ref.effekt +++ b/libraries/common/ref.effekt @@ -9,15 +9,11 @@ extern js """ } """ -/** - * Global, mutable references - */ +/// Global, mutable references extern type Ref[T] -/** - * Allocates a new reference of size `size`, keeping its value _undefined_. - * Prefer using `ref` constructor instead to ensure that the value is defined. - */ +/// Allocates a new reference of size `size`, keeping its value _undefined_. +/// Prefer using `ref` constructor instead to ensure that the value is defined. extern global def allocate[T](): Ref[T] = js "{ value: undefined }" chez "(box #f)" @@ -26,9 +22,7 @@ extern global def allocate[T](): Ref[T] = ret %Pos %z """ -/** - * Creates a new reference with the initial value `init`. - */ +/// Creates a new reference with the initial value `init`. extern global def ref[T](init: T): Ref[T] = js "{ value: ${init} }" chez "(box ${init})" @@ -37,9 +31,7 @@ extern global def ref[T](init: T): Ref[T] = ret %Pos %z """ -/** - * Gets the referenced element of the `ref` in constant time. - */ +/// Gets the referenced element of the `ref` in constant time. extern global def get[T](ref: Ref[T]): T = js "${ref}.value" chez "(unbox ${ref})" @@ -48,13 +40,11 @@ extern global def get[T](ref: Ref[T]): T = ret %Pos %z """ -/** - * Sets the referenced element of the `ref` to `value` in constant time. - */ +/// Sets the referenced element of the `ref` to `value` in constant time. extern global def set[T](ref: Ref[T], value: T): Unit = js "set$impl(${ref}, ${value})" chez "(set-box! ${ref} ${value})" llvm """ %z = call %Pos @c_ref_set(%Pos ${ref}, %Pos ${value}) ret %Pos %z - """ \ No newline at end of file + """ diff --git a/libraries/common/result.effekt b/libraries/common/result.effekt index 02d34762e..a1d03a088 100644 --- a/libraries/common/result.effekt +++ b/libraries/common/result.effekt @@ -4,18 +4,14 @@ import effekt import option import exception -/** - * Represents the result of a potentially failing computation. - * It is the "reification" of the Exception[E] effect. - */ +/// Represents the result of a potentially failing computation. +/// It is the "reification" of the Exception[E] effect. type Result[A, E] { Error(exception: E, msg: String); Success(a: A) } -/** - * Represent ("reify") the result of a potentially failing computation. - */ +/// Represent ("reify") the result of a potentially failing computation. def result[A, E] { f: => A / Exception[E] }: Result[A, E] = try { Success(f()) } with Exception[E] { @@ -27,18 +23,14 @@ def result[A, E](proxy: on[E]) { f: => A / Exception[E] }: Result[A, E] = try { def raise(exc, msg) = Error(exc, msg) } -/** - * Extracts the value of a result, if available - * Monadic "reflection" - */ +/// Extracts the value of a result, if available +/// Monadic "reflection" def value[A, E](r: Result[A, E]): A / Exception[E] = r match { case Success(a) => a case Error(exc, msg) => do raise(exc, msg) } -/** - * Converts a result to an option forgetting the error details - */ +/// Converts a result to an option forgetting the error details def toOption[A, E](r: Result[A, E]): Option[A] = r match { case Success(a) => Some(a) case Error(exc, msg) => None() diff --git a/libraries/common/seq.effekt b/libraries/common/seq.effekt index bc52c72f6..76af81ac8 100644 --- a/libraries/common/seq.effekt +++ b/libraries/common/seq.effekt @@ -1,41 +1,32 @@ +/// This file implements the [[Seq]] type as a general purpose functional sequence. +/// +/// Implemented as a 2-3 finger tree, it supports +/// - prepend and append in amortized O(1), +/// - concat(m, n) in O(log(min(m, n))) +/// - first and last in amortized O(1) +/// - size in amortized O(1) +/// +/// More information on finger trees: +/// https://www.staff.city.ac.uk/~ross/papers/FingerTree.pdf module seq -/** - * This file implements the [[Seq]] type as a general purpose functional sequence. - * - * Implemented as a 2-3 finger tree, it supports - * - prepend and append in amortized O(1), - * - concat(m, n) in O(log(min(m, n))) - * - first and last in amortized O(1) - * - size in amortized O(1) - * - * More information on finger trees: - * https://www.staff.city.ac.uk/~ross/papers/FingerTree.pdf - */ - -/** - * Sequences of elements - * - * They are represented as 2-3 finger trees. - */ +/// Sequences of elements +/// +/// They are represented as 2-3 finger trees. type Seq[A] { Empty() Single(value: A) Deep(size: Int, prefix: Digit[A], middle: Tree[A], suffix: Digit[A]) } -/** - * Result of splitting a sequence at the front or back. - */ +/// Result of splitting a sequence at the front or back. type View[A] { IsEmpty() View(element: A, remainder: Seq[A]) } -/** - * Exception[NoSuchElement] is raised when accessing non-existing elements - * or splitting empty collections. - */ +/// Exception[NoSuchElement] is raised when accessing non-existing elements +/// or splitting empty collections. record NoSuchElement() @@ -61,11 +52,9 @@ record IndexOutOfBounds() // Internal Types // -------------- -/** - * Internal grouping of 1-4 elements - * - * It is called digit since Okasaki (1998) calls finger trees "numerical operations". - */ +/// Internal grouping of 1-4 elements +/// +/// It is called digit since Okasaki (1998) calls finger trees "numerical operations". type Digit[A] { One(value: A) Two(first: A, second: A) @@ -73,9 +62,7 @@ type Digit[A] { Four(first: A, second: A, third: A, fourth: A) } -/** - * Internal representation of a 2-3 tree - */ +/// Internal representation of a 2-3 tree type Node[A] { // These are necessary to avoid polymorphic recursion Leaf2(first: A, second: A) @@ -84,12 +71,10 @@ type Node[A] { Node3(size: Int, first: Node[A], second: Node[A], third: Node[A]) } -/** - * Internal duplicate of Seq - * - * splitting into two type parameters is necessary since our MLton backend does - * not support mutually recursive data type declarations. - */ +/// Internal duplicate of Seq +/// +/// splitting into two type parameters is necessary since our MLton backend does +/// not support mutually recursive data type declarations. type Finger[A, N] { NoFinger() SingleFinger(value: Node[A]) @@ -141,9 +126,7 @@ def size[A](tree: Tree[A]): Int = tree match { case DeepFinger(size, _, _, _) => size } -/** - * The size of the given sequence - */ +/// The size of the given sequence def size[A](seq: Seq[A]): Int = seq match { case Empty() => 0 case Single(value) => 1 @@ -408,9 +391,7 @@ def reverse[A](seq: Seq[A]): Seq[A] = { } -/** - * Random access - */ +/// Random access def index[A](seq: Seq[A], index: Int): A / Exception[NoSuchElement] = { // invariant for all internal functions: element is in the sequence @@ -485,9 +466,7 @@ def index[A](seq: Seq[A], index: Int): A / Exception[NoSuchElement] = { } } -/** - * Random access - */ +/// Random access def update[A](seq: Seq[A], index: Int, value: A): Seq[A] / Exception[NoSuchElement] = { // invariant for all internal functions: element is in the sequence @@ -911,4 +890,4 @@ def map[A, B](seq: Seq[A]) { f: (A) {Control} => B }: Seq[B] = { // TODO equality comparison -// \ No newline at end of file +// diff --git a/libraries/common/string.effekt b/libraries/common/string.effekt index 0148ffa97..523fc5fba 100644 --- a/libraries/common/string.effekt +++ b/libraries/common/string.effekt @@ -34,9 +34,7 @@ def substring(str: String, from: Int): String = str.substring(from, str.length) -/** - * Checks whether str starts with the given prefix at `from` - */ +/// Checks whether str starts with the given prefix at `from` def isSubstringAt(str: String, prefix: String, from: Int): Bool = { with default[OutOfBounds, Bool] { false }; @@ -59,11 +57,9 @@ def startsWith(str: String, prefix: String): Bool = def endsWith(str: String, suffix: String): Bool = isSubstringAt(str, suffix, str.length - suffix.length) -/** - * Repeats the given string n-times. - * - * TODO use a more efficient way of appending strings like a buffer - */ +/// Repeats the given string n-times. +/// +/// TODO use a more efficient way of appending strings like a buffer def repeat(str: String, n: Int): String = { def go(n: Int, result: String): String = { if (n == 0) result @@ -180,15 +176,13 @@ def toInt(str: String, base: Int): Int / Exception[WrongFormat] = { } } -// Native versions of toInt (unused right now) +/// Native versions of toInt (unused right now) extern pure def unsafeToInt(str: String): Int = js "(Number.isNaN(parseInt(${str})) ? undefined : parseInt(${str}))" chez "(string->number ${str})" -/** - * Returns the index of the first occurrence of `sub` in `str` - */ +/// Returns the index of the first occurrence of `sub` in `str` def indexOf(str: String, sub: String): Option[Int] = indexOf(str, sub, 0) @@ -202,9 +196,7 @@ def indexOf(str: String, sub: String, from: Int): Option[Int] = { go(from) } -/** - * Returns the index of the last occurence of `sub` in `str` - */ +/// Returns the index of the last occurence of `sub` in `str` def lastIndexOf(str: String, sub: String): Option[Int] = lastIndexOf(str, sub, str.length)