--- title: "Standard Library: Core, R Interop, and Testing" output: arl::arl_html_vignette pkgdown: as_is: true vignette: > %\VignetteIndexEntry{Standard Library: Core, R Interop, and Testing} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") arl::register_knitr_engine() ``` *Examples on this page may reference functions from other stdlib modules without showing explicit `(import ...)` statements. In the REPL or your own code, you will need to import non-prelude modules before using their exports — see [Importing modules](lang-reference.html#importing-modules).* ## Special Forms {#section-special-forms} ### quote {#quote} Return expr without evaluating it. The shorthand `'expr` is equivalent. **Signature:** `(quote expr)` **Examples:** ```{arl, eval=FALSE} (quote (+ 1 2)) ; => (+ 1 2) '(a b c) ; => (a b c) ``` ```{arl, include=FALSE} (assert-equal '(+ 1 2) (quote (+ 1 2))) (assert-equal '(a b c) '(a b c)) ``` **See also:** [quasiquote](#quasiquote), [eval](#eval) --- ### if {#if} Evaluate then or else based on test truthiness. **Signature:** `(if test then [else])` **Examples:** ```{arl, eval=FALSE} (if (> 3 2) "yes" "no") ; => "yes" (if #f 1) ; => #nil ``` ```{arl, include=FALSE} (assert-equal "yes" (if (> 3 2) "yes" "no")) (assert-equal #nil (if #f 1)) ``` **See also:** [and](#and), [or](#or) --- ### define {#define} Bind a name in the current lexical environment. **Signature:** `(define name value)` **Examples:** ```{arl, eval=FALSE} (define x 42) (define add (lambda (a b) (+ a b))) ``` ```{arl, include=FALSE} (define sf-define-x 42) (assert-equal 42 sf-define-x) (define sf-add (lambda (a b) (+ a b))) (assert-equal 5 (sf-add 2 3)) ``` **See also:** [set!](#set-bang), [lambda](#lambda) --- ### set! {#set-bang} Update an existing binding in the current environment chain. **Signature:** `(set! name value)` **Examples:** ```{arl, eval=FALSE} (define x 1) (set! x (+ x 1)) ; x => 2 ``` ```{arl, include=FALSE} (define sf-set-x 1) (set! sf-set-x (+ sf-set-x 1)) (assert-equal 2 sf-set-x) ``` **See also:** [define](#define) --- ### lambda {#lambda} Create an anonymous function with lexical scope. **Signature:** `(lambda (params...) body...)` **Examples:** ```{arl, eval=FALSE} ((lambda (x) (+ x 1)) 41) ; => 42 ``` ```{arl, include=FALSE} (assert-equal 42 ((lambda (x) (+ x 1)) 41)) ``` **See also:** [define](#define) --- ### begin {#begin} Evaluate expressions in sequence and return the final result. **Signature:** `(begin expr...)` **Examples:** ```{arl, eval=FALSE} (begin (define x 1) (set! x (+ x 1)) x) ; => 2 ``` ```{arl, include=FALSE} (assert-equal 2 (begin (define sf-begin-x 1) (set! sf-begin-x (+ sf-begin-x 1)) sf-begin-x)) ``` **See also:** [if](#if) --- ### defmacro {#defmacro} Define a macro that transforms code before evaluation. **Signature:** `(defmacro name (params...) body...)` **Examples:** ```{arl, eval=FALSE} (defmacro when (test . body) `(if ,test (begin ,@body) #nil)) ``` ```{arl, include=FALSE} (defmacro sf-when (test . body) `(if ,test (begin ,@body) #nil)) (assert-equal 3 (sf-when #t (+ 1 2))) ``` **See also:** [macroexpand](#macroexpand), [macroexpand-1](#macroexpand-1), [quasiquote](#quasiquote) --- ### quasiquote {#quasiquote} Build code/data templates with selective evaluation. The shorthand `` `expr `` is equivalent. **Signature:** `(quasiquote expr)` **Examples:** ```{arl, eval=FALSE} (define x 10) `(a ,x c) ; => (a 10 c) ``` ```{arl, include=FALSE} (define sf-qq-x 10) (assert-equal '(a 10 c) `(a ,sf-qq-x c)) ``` **See also:** [quote](#quote), [unquote](#unquote), [unquote-splicing](#unquote-splicing) --- ### unquote {#unquote} Evaluate expr inside a quasiquote template. Within a template, the shorthand `,expr` is equivalent. **Signature:** `(unquote expr)` **Examples:** ```{arl, eval=FALSE} (define x 10) `(a ,x c) ; => (a 10 c) ``` ```{arl, include=FALSE} (define sf-uq-x 10) (assert-equal '(a 10 c) `(a ,sf-uq-x c)) ``` **See also:** [quasiquote](#quasiquote), [unquote-splicing](#unquote-splicing) --- ### unquote-splicing {#unquote-splicing} Splice list elements into a quasiquoted list. Within a quasiquote template, the shorthand `,@expr` is equivalent. **Signature:** `(unquote-splicing expr)` **Examples:** ```{arl, eval=FALSE} (define xs '(2 3)) `(1 ,@xs 4) ; => (1 2 3 4) ``` ```{arl, include=FALSE} (define sf-uqs-xs '(2 3)) (assert-equal '(1 2 3 4) `(1 ,@sf-uqs-xs 4)) ``` **See also:** [quasiquote](#quasiquote), [unquote](#unquote) --- ### and {#and} Short-circuit logical conjunction. **Signature:** `(and expr...)` **Examples:** ```{arl, eval=FALSE} (and #t 1 2) ; => 2 (and #f (stop "error")) ; => #f (second form not evaluated) ``` ```{arl, include=FALSE} (assert-equal 2 (and #t 1 2)) (assert-equal #f (and #f (stop "error"))) ``` **See also:** [or](#or), [if](#if) --- ### or {#or} Short-circuit logical disjunction. **Signature:** `(or expr...)` **Examples:** ```{arl, eval=FALSE} (or #f #nil 0 7) ; => 7 (or #t (stop "error")) ; => #t (second form not evaluated) ``` ```{arl, include=FALSE} (assert-equal 7 (or #f #nil 0 7)) (assert-equal #t (or #t (stop "error"))) ``` **See also:** [and](#and), [if](#if) --- ### while {#while} Repeatedly evaluate body while condition remains truthy. **Signature:** `(while test body...)` **Examples:** ```{arl, eval=FALSE} (define i 0) (while (< i 3) (set! i (+ i 1))) i ; => 3 ``` ```{arl, include=FALSE} (define sf-while-i 0) (while (< sf-while-i 3) (set! sf-while-i (+ sf-while-i 1))) (assert-equal 3 sf-while-i) ``` **See also:** [begin](#begin) --- ### delay {#delay} Create a promise that delays evaluation of expr until forced. **Signature:** `(delay expr)` **Examples:** ```{arl, eval=FALSE} (define p (delay (+ 1 2))) (force p) ; => 3 ``` ```{arl, include=FALSE} (define sf-delay-p (delay (+ 1 2))) (assert-true (promise? sf-delay-p)) (assert-equal 3 (force sf-delay-p)) ``` **See also:** [force](#force), [promise?](#promise-p), [promise-expr](#promise-expr) --- ### import {#import} Load a module and bind it as a first-class value. By default, `(import name)` binds the module environment to the symbol `name` for qualified access via `name/sym`. Use `:refer` to bring specific exports (or all exports) into scope unqualified. Use `:as` to alias the module binding. **Signature:** `(import name) (import name :refer (sym1 sym2 ...)) (import name :refer :all) (import name :as alias) (import name :rename ((old new) ...)) (import name :reload) (import "path/to/file.arl")` **Examples:** ```{arl, eval=FALSE} (import math) (math/inc 5) ; qualified access (import math :refer :all) (inc 5) ; unqualified access (import math :as m) (m/inc 5) ; aliased qualified access ``` **See also:** [module](#module), [load](#load), [module-ref](#module-ref) --- ### module {#module} Define a module with explicit exports. A named module registers itself in the module registry. A nameless module derives its name from the source file. `export-all` exports all non-private definitions; add `:re-export` to also re-export imported symbols. **Signature:** `(module name (export ...) body...) (module (export ...) body...) (module name (export-all) body...) (module name (export-all :re-export) body...)` **Examples:** ```{arl, eval=FALSE} (module demo (export answer) (define answer 42)) ``` ```{arl, include=FALSE} (module sf-demo (export sf-answer) (define sf-answer 42)) (import sf-demo :refer :all) (assert-equal 42 sf-answer) ``` **See also:** [import](#import), [module?](#module-p), [module-exports](#module-exports), [module-name](#module-name) --- ## Error and Warning {#section-error-and-warning} ### error {#error} Signal an error with message. **Signature:** `(error msg)` **Parameters:** - **`msg`** — Error message string **Examples:** ```{arl} (try-catch (error "something went wrong") (catch e ($ e "message"))) ; => "something went wrong" (try-catch (error "oops") (catch e "caught")) ; => "caught" ``` ```{arl, include=FALSE} (assert-equal "something went wrong" (try-catch (error "something went wrong") (catch e ($ e "message")))) (assert-equal "caught" (try-catch (error "oops") (catch e "caught"))) ``` **See also:** [warn](#warn), [assert](#assert), [try-catch](lang-control.html#try-catch) --- ### warn {#warn} Emit warning with message. **Signature:** `(warn msg)` **Parameters:** - **`msg`** — Warning message string **Examples:** ```{arl} (warn "check your input") ; emits warning, returns #nil ``` **See also:** [error](#error), [trace](lang-strings-io.html#trace) --- ## Identity and Values {#section-identity-and-values} ### identity {#identity} Return argument. **Signature:** `(identity x)` **Parameters:** - **`x`** — Value to return unchanged **Examples:** ```{arl} (identity 42) ; => 42 (identity "hello") ; => "hello" (map identity '(1 2 3)) ; => (1 2 3) ``` ```{arl, include=FALSE} (assert-equal 42 (identity 42)) (assert-equal "hello" (identity "hello")) ``` **See also:** [map](lang-functional.html#map) --- ### values {#values} Return multiple values to a call-with-values consumer. **Signature:** `(values args...)` **Parameters:** - **`args`** — Values to package together **Examples:** ```{arl} (values 1 2 3) ; => multiple-values container ``` ```{arl, include=FALSE} (assert-true (values? (values 1 2 3))) ``` **See also:** [values?](#values-p), [call-with-values](#call-with-values) --- ### values? {#values-p} Return #t if x is a multiple-values container. **Signature:** `(values? x)` **Parameters:** - **`x`** — Value to test **Examples:** ```{arl} (values? (values 1 2)) ; => #t (values? 42) ; => #f ``` ```{arl, include=FALSE} (assert-true (values? (values 1 2))) (assert-false (values? 42)) ``` **See also:** [values](#values), [call-with-values](#call-with-values) --- ### call-with-values {#call-with-values} Call producer and pass its values to consumer. **Signature:** `(call-with-values producer consumer)` **Parameters:** - **`producer`** — Zero-argument function that returns values - **`consumer`** — Function that receives the produced values as arguments **Examples:** ```{arl} (call-with-values (lambda () (values 1 2)) (lambda (a b) (+ a b))) ; => 3 ``` ```{arl, include=FALSE} (assert-equal 3 (call-with-values (lambda () (values 1 2)) (lambda (a b) (+ a b)))) ``` **See also:** [values](#values), [values?](#values-p) --- ## Function Application {#section-function-application} ### funcall {#funcall} Apply a function with a provided list of arguments. **Signature:** `(funcall fn args)` **Parameters:** - **`fn`** — Function to apply - **`args`** — List of arguments to pass to fn **Examples:** ```{arl} (funcall + (list 1 2 3)) ; => 6 (funcall c (list 1 2 3)) ; => c(1, 2, 3) ``` ```{arl, include=FALSE} (assert-equal 6 (funcall + (list 1 2 3))) ``` **See also:** apply, [r-call](#r-call) --- ### r-call {#r-call} Call an R function with optional environment. Searches from .GlobalEnv by default, finding base and loaded package functions. **Signature:** `(r-call fn [args (list])` **Parameters:** - **`fn`** — Symbol or string naming the R function - **`args`** — List of arguments to pass (default empty) - **`envir`** — Environment to search for fn (default .GlobalEnv) **Examples:** ```{arl} (r-call "mean" (list (c 1 2 3))) ; => 2 (r-call "ls" (list)) ; list .GlobalEnv bindings (r-call "Sys.time" (list)) ; current time ``` ```{arl, include=FALSE} (assert-equal 2 (r-call "mean" (list (c 1 2 3)))) ``` **Note:** R functions are directly available in Arl without `r-call`. Use `r-call` when you need to look up a function by string name or specify the search environment. **See also:** [funcall](#funcall), [r-eval](#r-eval) --- ### get {#get} Get a binding by name, defaulting to .GlobalEnv. **Signature:** `(get name [envir] [inherits])` **Parameters:** - **`name`** — Symbol or string naming the binding to look up - **`envir`** — Environment to search in (default .GlobalEnv) - **`inherits`** — Whether to search parent environments (default #t) **Examples:** ```{arl} (get "mean") ; => the `mean` function (get "pi" (baseenv)) ; => 3.141593 ``` ```{arl, include=FALSE} (assert-true (is.function (get "mean"))) (assert-true (> (get "pi" (baseenv)) 3.14)) ``` **See also:** [r-call](#r-call) --- ### unbind-variable {#unbind-variable} Remove a variable binding from an environment. **Signature:** `(unbind-variable name [envir])` **Parameters:** - **`name`** — Symbol or string naming the variable to remove - **`envir`** — Environment to remove from (default current environment) **Examples:** ```{arl} (begin (define tmp-var 42) (unbind-variable "tmp-var" (current-env)) (try-catch tmp-var (catch e "gone"))) ; => "gone" ``` ```{arl, include=FALSE} (assert-equal "gone" (begin (define ub-test 1) (unbind-variable "ub-test" (current-env)) (try-catch ub-test (catch e "gone")))) ``` **See also:** [get](#get), [define](#define) --- ### run {#run} Evaluate a file in an isolated child environment. Uses `parent` as the child environment parent. Definitions/imports in the loaded file remain in the child and are not visible in `parent`. **Signature:** `(run path [parent])` **Parameters:** - **`path`** — File path to evaluate - **`parent`** — Parent environment for the child (default current environment) **Examples:** ```{arl} (define run-demo-path (tempfile :fileext ".arl")) (writeLines (c "(define run-demo-val 1)") run-demo-path) (run run-demo-path) (assert-equal "missing" (try-catch run-demo-val (catch e "missing"))) (unlink run-demo-path) ``` **See also:** [load](#load), [current-env](#current-env) --- ## License {#section-license} ### license {#license} Display Arl and R license information. **Signature:** `(license)` **Examples:** ```{arl} (license) ; prints Arl and R license info ``` --- ## Macro Introspection {#section-macro-introspection} ### macroexpand-1 {#macroexpand-1} Expand one layer of macros in expr. **Signature:** `(macroexpand-1 expr)` **Parameters:** - **`expr`** — Expression to macro-expand **Examples:** ```{arl} (macroexpand-1 '(when #t 42)) ; => (if #t (begin 42) #nil) ``` ```{arl, include=FALSE} (assert-equal '(if #t (begin 42) #nil) (macroexpand-1 '(when #t 42))) ``` **See also:** [macroexpand](#macroexpand), [macroexpand-all](#macroexpand-all) --- ### macroexpand-all {#macroexpand-all} Fully expand all macros in expr. Same as macroexpand with no depth. **Parameters:** - **`expr`** — Expression to recursively macro-expand **Examples:** ```{arl} (macroexpand-all '(when #t 42)) ; => (if #t (begin 42) #nil) ``` ```{arl, include=FALSE} (assert-equal '(if #t (begin 42) #nil) (macroexpand-all '(when #t 42))) ``` **See also:** [macroexpand](#macroexpand), [macroexpand-1](#macroexpand-1) --- ## R Nonstandard Evaluation Wrappers {#section-r-nonstandard-evaluation-wrappers} These macros provide Arl-friendly interfaces to R functions that use nonstandard evaluation (NSE). They automatically quote expressions so you can write natural Arl code without manual quoting. ### suppressWarnings {#suppresswarnings} Suppress warnings generated by evaluating expr. **Signature:** `(suppressWarnings expr)` **Parameters:** - **`expr`** — Expression to evaluate with warnings suppressed **Examples:** ```{arl} (suppressWarnings (as.numeric "not a number")) ; => NA (warning suppressed) (suppressWarnings (log -1)) ; => NaN (warning suppressed) ``` ```{arl, include=FALSE} (assert-true (is.na (suppressWarnings (as.numeric "not a number")))) (assert-true (is.nan (suppressWarnings (log -1)))) ``` **See also:** [suppressMessages](#suppressmessages) --- ### suppressMessages {#suppressmessages} Suppress messages generated by evaluating expr. **Signature:** `(suppressMessages expr)` **Parameters:** - **`expr`** — Expression to evaluate with messages suppressed **Examples:** ```{arl} (suppressMessages (message "hello")) ; => #nil (message suppressed) ``` ```{arl, include=FALSE} (assert-true (is.null (suppressMessages (message "hello")))) ``` **See also:** [suppressWarnings](#suppresswarnings) --- ### with {#with} Evaluate expr in the context of data (a data frame or list). **Signature:** `(with data expr)` **Parameters:** - **`data`** — Data frame or list providing the evaluation context - **`expr`** — Expression evaluated with data columns as variables **Examples:** ```{arl} (define df (data.frame :x (c 1 2 3) :y (c 4 5 6))) (with df (+ x y)) ; => c(5, 7, 9) ``` ```{arl, include=FALSE} (assert-equal (c 5 7 9) (with (data.frame :x (c 1 2 3) :y (c 4 5 6)) (+ x y))) ``` **See also:** [within](#within) --- ### within {#within} Evaluate expr within data, returning modified data. **Signature:** `(within data expr)` **Parameters:** - **`data`** — Data frame to modify - **`expr`** — Expression that can assign new/modified columns **Examples:** ```{arl} (define df (data.frame :x (c 1 2 3))) (within df (<- z (* x 2))) ; returns df with new column z ``` ```{arl, include=FALSE} (assert-true (%in% "z" (names (within (data.frame :x (c 1 2 3)) (<- z (* x 2)))))) ``` **See also:** [with](#with) --- ### subset {#subset} Subset x using condition. Optional rest args for select, drop, etc. **Signature:** `(subset x condition rest...)` **Parameters:** - **`x`** — Data frame to subset - **`condition`** — Row-selection expression evaluated in x's context - **`rest`** — Optional additional arguments (e.g. select) **Examples:** ```{arl} (define df (data.frame :x (c 1 2 3) :y (c 10 20 30))) (subset df (> x 1)) ; rows where x > 1 ``` ```{arl, include=FALSE} (assert-equal 2L (nrow (subset (data.frame :x (c 1 2 3) :y (c 10 20 30)) (> x 1)))) ``` **See also:** [with](#with), [within](#within) --- ### transform {#transform} transform is difficult to implement - use within() or dplyr::mutate() instead. **Signature:** `(transform args...)` **Parameters:** - **`args`** — Arguments (not used; always signals an error) **Note:** Not yet supported due to R named-argument syntax. Use `within` or `dplyr::mutate` instead. **See also:** [within](#within) --- ### substitute {#substitute} Perform substitution in an expression, or error if called with 1 arg. **Signature:** `(substitute args...)` **Parameters:** - **`args`** — Expression and environment for substitution **Note:** Single-argument `substitute` does not work in Arl due to eager evaluation. Use macros or explicit quoting instead. Two-argument form works normally. **See also:** [defmacro](#defmacro) --- ## Assertion Helpers {#section-assertion-helpers} These functions provide test-style assertions that signal errors on failure and return `#t` on success. ### assert {#assert} Assert condition or raise error. **Signature:** `(assert cond [msg "Assertion failed"])` **Parameters:** - **`cond`** — Condition to test - **`msg`** — Error message if assertion fails (default "Assertion failed") **Examples:** ```{arl, eval=FALSE} (assert #t) ; => #t (assert (> 3 2)) ; => #t (assert #f "must be true") ; signals "must be true" (assert #f) ; signals "Assertion failed" ``` ```{arl, include=FALSE} (assert-true (assert #t)) (assert-true (assert (> 3 2))) (assert-error (assert #f "must be true")) (assert-error (assert #f)) ``` **See also:** [error](#error) --- ### assert-equal {#assert-equal} Assert expected and actual are equal?. **Signature:** `(assert-equal expected actual)` **Parameters:** - **`expected`** — Expected value - **`actual`** — Actual value to compare **Examples:** ```{arl, eval=FALSE} (assert-equal 3 (+ 1 2)) ; => #t (assert-equal "a" "a") ; => #t (assert-equal 1 2) ; signals error ``` ```{arl, include=FALSE} (assert-true (assert-equal 3 (+ 1 2))) (assert-true (assert-equal "a" "a")) (assert-error (assert-equal 1 2)) ``` **See also:** [assert-eq](#assert-eq), [assert-true](#assert-true) --- ### assert-true {#assert-true} Assert value is truthy. **Signature:** `(assert-true value)` **Parameters:** - **`value`** — Value expected to be truthy **Examples:** ```{arl, eval=FALSE} (assert-true #t) ; => #t (assert-true 1) ; => #t (assert-true #f) ; signals error ``` ```{arl, include=FALSE} (assert-true (assert-true #t)) (assert-true (assert-true 1)) (assert-error (assert-true #f)) ``` **See also:** [assert-false](#assert-false), [assert](#assert) --- ### assert-false {#assert-false} Assert value is falsy. **Signature:** `(assert-false value)` **Parameters:** - **`value`** — Value expected to be falsy **Examples:** ```{arl, eval=FALSE} (assert-false #f) ; => #t (assert-false #nil) ; => #t (assert-false #t) ; signals error ``` ```{arl, include=FALSE} (assert-true (assert-false #f)) (assert-true (assert-false #nil)) (assert-error (assert-false #t)) ``` **See also:** [assert-true](#assert-true), [assert](#assert) --- ### assert-eq {#assert-eq} Assert expected and actual are identical (R's `identical()`). **Signature:** `(assert-eq expected actual)` **Parameters:** - **`expected`** — Expected value - **`actual`** — Actual value to compare with identical? **Examples:** ```{arl, eval=FALSE} (assert-eq 42 42) ; => #t (assert-eq "abc" "abc") ; => #t (assert-eq 1 1L) ; signals error (double vs integer) (assert-eq 1 "1") ; signals error (different types) ``` ```{arl, include=FALSE} (assert-true (assert-eq 42 42)) (assert-true (assert-eq "abc" "abc")) (assert-error (assert-eq 1 "1")) ``` **Note:** Uses R's `identical()`, which checks exact structural identity including type. `1` (double) and `1L` (integer) are not identical. Use `assert-equal` for value comparison with `equal?`. **See also:** [assert-equal](#assert-equal), [assert](#assert) --- ### assert-error {#assert-error} Assert expression throws an error. **Signature:** `(assert-error expr)` **Parameters:** - **`expr`** — Expression expected to signal an error **Examples:** ```{arl, eval=FALSE} (assert-error (error "boom")) ; => #t (assert-error (stop "fail")) ; => #t (assert-error 42) ; signals error ``` ```{arl, include=FALSE} (assert-true (assert-error (error "boom"))) (assert-true (assert-error (stop "fail"))) (assert-error (assert-error 42)) ``` **See also:** [assert](#assert), [error](#error) --- ### assert-no-error {#assert-no-error} Assert expression does not throw an error. **Signature:** `(assert-no-error expr)` **Parameters:** - **`expr`** — Expression expected to complete without error **Examples:** ```{arl, eval=FALSE} (assert-no-error 42) ; => #t (assert-no-error (+ 1 2)) ; => #t (assert-no-error (error "boom")) ; signals error ``` ```{arl, include=FALSE} (assert-true (assert-no-error 42)) (assert-true (assert-no-error (+ 1 2))) (assert-error (assert-no-error (error "boom"))) ``` **See also:** [assert-error](#assert-error), [assert](#assert) --- ## Arithmetic {#section-arithmetic} ### + {#plus} Variadic addition. With no arguments returns 0 (additive identity). With one argument returns it unchanged. With two or more, returns their sum left-to-right. **Signature:** `(+ a ...)` **Examples:** ```{arl} (+) ; => 0 (+ 5) ; => 5 (+ 1 2 3) ; => 6 ``` ```{arl, include=FALSE} (assert-equal 0 (+)) (assert-equal 5 (+ 5)) (assert-equal 6 (+ 1 2 3)) ``` **See also:** [-](#minus), [*](#star), [/](#div) --- ### * {#star} Variadic multiplication. With no arguments returns 1 (multiplicative identity). With one argument returns it unchanged. With two or more, returns their product left-to-right. **Signature:** `(* a ...)` **Examples:** ```{arl} (*) ; => 1 (* 5) ; => 5 (* 2 3 4) ; => 24 ``` ```{arl, include=FALSE} (assert-equal 1 (*)) (assert-equal 5 (* 5)) (assert-equal 24 (* 2 3 4)) ``` **See also:** [+](#plus), [-](#minus), [/](#div) --- ### - {#minus} Variadic subtraction. Requires at least one argument. With one argument returns its negation. With two or more, subtracts subsequent arguments from the first left-to-right. **Signature:** `(- a ...)` **Examples:** ```{arl} (- 5) ; => -5 (- 10 3) ; => 7 (- 10 3 2) ; => 5 ``` ```{arl, include=FALSE} (assert-equal -5 (- 5)) (assert-equal 7 (- 10 3)) (assert-equal 5 (- 10 3 2)) ``` **See also:** [+](#plus), [*](#star), [/](#div) --- ### / {#div} Variadic division. Requires at least one argument. With one argument returns its reciprocal. With two or more, divides the first argument by subsequent arguments left-to-right. **Signature:** `(/ a ...)` **Examples:** ```{arl} (/ 5) ; => 0.2 (/ 10 2) ; => 5 (/ 100 5 2) ; => 10 ``` ```{arl, include=FALSE} (assert-equal 0.2 (/ 5)) (assert-equal 5 (/ 10 2)) (assert-equal 10 (/ 100 5 2)) ``` **See also:** [+](#plus), [-](#minus), [*](#star) --- ## Comparison {#section-comparison} ### < {#lt} Variadic less-than. With fewer than two arguments returns #t (vacuously true). With two or more, checks that each argument is strictly less than the next (chained pairwise comparison). **Signature:** `(< a b ...)` **Examples:** ```{arl} (< 1 2) ; => #t (< 1 2 3) ; => #t (< 1 3 2) ; => #f ``` ```{arl, include=FALSE} (assert-true (< 1 2)) (assert-true (< 1 2 3)) (assert-false (< 1 3 2)) ``` **See also:** [<=](#lte), [>](#gt), [>=](#gte), [=](#num-eq) --- ### <= {#lte} Variadic less-than-or-equal. With fewer than two arguments returns #t. With two or more, checks that each argument is less than or equal to the next. **Signature:** `(<= a b ...)` **Examples:** ```{arl} (<= 1 2) ; => #t (<= 1 1 2) ; => #t (<= 2 1) ; => #f ``` ```{arl, include=FALSE} (assert-true (<= 1 2)) (assert-true (<= 1 1 2)) (assert-false (<= 2 1)) ``` **See also:** [<](#lt), [>](#gt), [>=](#gte), [=](#num-eq) --- ### > {#gt} Variadic greater-than. With fewer than two arguments returns #t. With two or more, checks that each argument is strictly greater than the next. **Signature:** `(> a b ...)` **Examples:** ```{arl} (> 3 2) ; => #t (> 3 2 1) ; => #t (> 3 1 2) ; => #f ``` ```{arl, include=FALSE} (assert-true (> 3 2)) (assert-true (> 3 2 1)) (assert-false (> 3 1 2)) ``` **See also:** [>=](#gte), [<](#lt), [<=](#lte), [=](#num-eq) --- ### >= {#gte} Variadic greater-than-or-equal. With fewer than two arguments returns #t. With two or more, checks that each argument is greater than or equal to the next. **Signature:** `(>= a b ...)` **Examples:** ```{arl} (>= 3 2) ; => #t (>= 2 2 1) ; => #t (>= 1 2) ; => #f ``` ```{arl, include=FALSE} (assert-true (>= 3 2)) (assert-true (>= 2 2 1)) (assert-false (>= 1 2)) ``` **See also:** [>](#gt), [<](#lt), [<=](#lte), [=](#num-eq) --- ### = {#num-eq} Variadic equality comparison (NULL-safe). With fewer than two arguments returns #t. With two or more, checks that all adjacent pairs are equal. NULL comparisons follow Scheme semantics: (= #nil #nil) is #t, (= #nil x) is #f. **Signature:** `(= a b ...)` **Examples:** ```{arl} (= 1 1) ; => #t (= 1 1 1) ; => #t (= 1 2) ; => #f (= "a" "a") ; => #t ``` ```{arl, include=FALSE} (assert-true (= 1 1)) (assert-true (= 1 1 1)) (assert-false (= 1 2)) (assert-true (= "a" "a")) ``` **Note:** Alias for ==. Both = and == are NULL-safe variadic equality. **See also:** [==](#num-eq-eq), [!=](#bang-eq), [<](#lt), [>](#gt) --- ### == {#num-eq-eq} Variadic equality comparison (NULL-safe). Identical to =. With fewer than two arguments returns #t. With two or more, checks that all adjacent pairs are equal. **Signature:** `(== a b ...)` **Examples:** ```{arl} (== 1 1) ; => #t (== 1 1 1) ; => #t (== 1 2) ; => #f ``` ```{arl, include=FALSE} (assert-true (== 1 1)) (assert-true (== 1 1 1)) (assert-false (== 1 2)) ``` **See also:** [=](#num-eq), [!=](#bang-eq), [<](#lt), [>](#gt) --- ### != {#bang-eq} Inequality comparison (NULL-safe). Returns #t if a and b are not equal. **Signature:** `(!= a b)` **Examples:** ```{arl} (!= 1 2) ; => #t (!= 1 1) ; => #f (!= #nil #nil) ; => #f ``` ```{arl, include=FALSE} (assert-true (!= 1 2)) (assert-false (!= 1 1)) (assert-false (!= #nil #nil)) ``` **See also:** [=](#num-eq), [==](#num-eq-eq) --- ### not {#not} Logical negation using Arl truthiness. Returns #t if x is falsy (0, #f, or #nil), #f otherwise. **Signature:** `(not x)` **Examples:** ```{arl} (not #f) ; => #t (not #nil) ; => #t (not 0) ; => #t (not 1) ; => #f (not "hi") ; => #f ``` ```{arl, include=FALSE} (assert-true (not #f)) (assert-true (not #nil)) (assert-true (not 0)) (assert-false (not 1)) (assert-false (not "hi")) ``` **See also:** [and](#and), [or](#or) --- ## Evaluation {#section-evaluation} ### eval {#eval} Evaluate a Arl expression in the current environment. **Signature:** `(eval expr)` **Examples:** ```{arl} (eval '(+ 1 2)) ; => 3 (eval '(list 1 2 3)) ; => (1 2 3) ``` ```{arl, include=FALSE} (assert-equal 3 (eval '(+ 1 2))) (assert-equal (list 1 2 3) (eval '(list 1 2 3))) ``` **See also:** [r-eval](#r-eval), [read](#read), [macroexpand](#macroexpand) --- ### read {#read} Parse a string into a Arl expression without evaluating it. **Signature:** `(read source)` **Examples:** ```{arl} (read "(+ 1 2)") ; => (+ 1 2) (unevaluated) (read "42") ; => 42 (read "foo") ; => foo (symbol) ``` ```{arl, include=FALSE} (assert-equal 42 (read "42")) (assert-equal 3 (eval (read "(+ 1 2)"))) ``` **Note:** Returns the first expression from the source string, or #nil if the string contains no expressions. Like R's parse(), but returns Arl S-expressions. **See also:** [eval](#eval), [read-from-string](lang-strings-io.html#read-from-string) --- ### write {#write} Convert a Arl expression to its string representation. The inverse of read. **Signature:** `(write expr)` **Examples:** ```{arl} (write '(+ 1 2)) ; => "(+ 1 2)" (write 42) ; => "42" (write "hello") ; => "\"hello\"" (write #t) ; => "#t" ``` ```{arl, include=FALSE} (assert-equal "42" (write 42)) (assert-equal "#t" (write #t)) ``` **Note:** Produces output that can be parsed back with read, ensuring the round-trip property: (read (write expr)) equals expr for any expression produced by read. **See also:** [read](#read), [eval](#eval), [format-value](lang-strings-io.html#format-value) --- ### load {#load} Load and evaluate an Arl source file in the target environment. Defaults to the current environment. **Signature:** `(load path [env])` **Examples:** ```{arl} (define __load_demo_path (tempfile :fileext ".arl")) (writeLines (c "(define __load_demo_value 42)") __load_demo_path) (load __load_demo_path) __load_demo_value (define __load_demo_env (new.env :parent (current-env))) (load __load_demo_path __load_demo_env) (get "__load_demo_value" __load_demo_env) (unlink __load_demo_path) ``` ```{arl, include=FALSE} (define __load_test_path (tempfile :fileext ".arl")) (writeLines (c "(define __load_test_value 7)") __load_test_path) (load __load_test_path) (assert-equal 7 __load_test_value) (define __load_test_env (new.env :parent (current-env))) (load __load_test_path __load_test_env) (assert-equal 7 (get "__load_test_value" __load_test_env)) (unlink __load_test_path) ``` **See also:** [eval](#eval), [read](#read), [run](#run), [current-env](#current-env) --- ### r-eval {#r-eval} Evaluate an R expression directly via R's eval(), bypassing Arl's compiler. **Signature:** `(r-eval expr)` **Examples:** ```{arl} (r-eval (quote (seq_len 5))) ; => c(1, 2, 3, 4, 5) ``` ```{arl, include=FALSE} (assert-equal (c 1 2 3 4 5) (r-eval (quote (seq_len 5)))) ``` **Note:** Useful for evaluating raw R calls that use R control flow (for, while) or other constructs that Arl normally overrides. **See also:** [eval](#eval), [r-call](#r-call) --- ## Documentation {#section-documentation} ### help {#help} Show help for a topic. Topic may be a symbol or string. Use :package to force R help lookup from a specific package. **Signature:** `(help topic [:package pkg])` **Examples:** ```{arl} (help if) (help "sum") (help "writeLines" :package "base") ``` ```{arl, include=FALSE} (assert-no-error (help if)) (assert-no-error (help "sum")) (assert-no-error (help "writeLines" :package "base")) ``` **See also:** [doc](#doc), [macroexpand](#macroexpand) --- ### doc! {#doc-bang} Attach documentation fields to a function. With a single string argument, sets the description (backward compatible). With keyword arguments, sets specific fields and merges with existing documentation. **Signature:** `(doc! fn "docstring") or (doc! fn :description "..." :examples "...")` **Examples:** ```{arl, eval=FALSE} (doc! my-fn "Doubles the input.") (doc! my-fn :examples "(my-fn 3) ; => 6") (doc! my-fn :description "Doubles." :note "Fast path.") ``` ```{arl, include=FALSE} (define __doc-test-fn (lambda (x) (* x 2))) (doc! __doc-test-fn "Doubles the input.") (assert-equal "Doubles the input." (doc __doc-test-fn)) (doc! __doc-test-fn :examples "(my-fn 3) ; => 6") (assert-equal "(my-fn 3) ; => 6" (doc __doc-test-fn "examples")) ``` **See also:** [doc](#doc), [help](#help) --- ### doc {#doc} Retrieve documentation from a function. With no field argument, returns the description. Pass a field name string to get a specific field, or "all" to get the full documentation list. **Signature:** `(doc fn) or (doc fn "field")` **Examples:** ```{arl, eval=FALSE} (doc my-fn) ; => "Doubles the input." (doc my-fn "examples") ; => "(my-fn 3) ; => 6" (doc my-fn "all") ; => named list of all fields ``` ```{arl, include=FALSE} (define __doc-get-fn (lambda (x) (+ x 1))) (doc! __doc-get-fn "Increments input.") (assert-equal "Increments input." (doc __doc-get-fn)) (doc! __doc-get-fn :note "Simple function.") (assert-equal "Simple function." (doc __doc-get-fn "note")) ``` **See also:** [doc!](#doc-bang), [help](#help) --- ## Macro Utilities {#section-macro-utilities} ### capture {#capture} Mark a symbol for intentional capture in a macro body, overriding hygiene. **Signature:** `(capture 'sym expr)` **Examples:** ```{arl} (defmacro aif (test then alt) `(let ((it ,test)) (if it ,(capture 'it then) ,(capture 'it alt)))) (aif (+ 2 3) it 0) ; => 5 ``` ```{arl, include=FALSE} (assert-equal 5 (aif (+ 2 3) it 0)) ``` **Note:** Use capture when writing anaphoric macros or other macros that intentionally introduce a binding visible to the caller. Without capture, Arl's automatic hygiene renames macro-introduced symbols to prevent accidental capture. **See also:** [gensym](#gensym), [macroexpand](#macroexpand), [defmacro](#defmacro) --- ### gensym {#gensym} Generate a unique uninterned symbol, useful for writing hygienic macros. **Signature:** `(gensym [prefix])` **Examples:** ```{arl} (gensym) ; => G1 (unique symbol) (gensym "tmp") ; => tmp2 (unique with prefix) ``` ```{arl, include=FALSE} (assert-true (symbol? (gensym))) (assert-true (symbol? (gensym "tmp"))) ``` **Note:** Each call returns a fresh symbol guaranteed not to conflict with user-defined names. The optional prefix defaults to "G". **See also:** [macroexpand](#macroexpand), [macroexpand-1](#macroexpand-1) --- ### macro? {#macro-p} Return #t if the symbol names a currently-defined macro. **Signature:** `(macro? sym)` **Examples:** ```{arl} (defmacro my-mac (x) x) (macro? 'my-mac) ; => #t (macro? 'car) ; => #f ``` ```{arl, include=FALSE} (assert-true (macro? 'my-mac)) (assert-false (macro? 'car)) ``` --- ### macroexpand {#macroexpand} Recursively expand all macros in expr until no macro calls remain. **Signature:** `(macroexpand expr)` **Examples:** ```{arl} (defmacro my-when (test body) `(if ,test ,body #nil)) (macroexpand '(my-when #t 42)) ; => (if #t 42 #nil) ``` ```{arl, include=FALSE} (assert-equal '(if #t 42 #nil) (macroexpand '(my-when #t 42))) ``` **Note:** Also available as `macroexpand-all` (alias). **See also:** [macroexpand-1](#macroexpand-1), [macro?](#macro-p), [gensym](#gensym) --- ## Promises (Lazy Evaluation) {#section-promises-lazy-evaluation} ### promise? {#promise-p} Return #t if x is a promise (created with `delay`). **Signature:** `(promise? x)` **Examples:** ```{arl} (define p (delay (+ 1 2))) (promise? p) ; => #t (promise? 42) ; => #f ``` ```{arl, include=FALSE} (define __p (delay (+ 1 2))) (assert-true (promise? __p)) (assert-false (promise? 42)) ``` **See also:** [force](#force), [promise-expr](#promise-expr) --- ### force {#force} Force a promise, evaluating its delayed expression and returning the result. If x is not a promise, returns x unchanged. **Signature:** `(force x)` **Examples:** ```{arl} (define p (delay (+ 1 2))) (force p) ; => 3 (force 42) ; => 42 (non-promise passed through) ``` ```{arl, include=FALSE} (define __fp (delay (+ 10 20))) (assert-equal 30 (force __fp)) (assert-equal 42 (force 42)) ``` **See also:** [promise?](#promise-p), [promise-expr](#promise-expr), [delay](#delay) --- ### promise-expr {#promise-expr} Extract the unevaluated expression from a promise. **Signature:** `(promise-expr p)` **Examples:** ```{arl} (define p (delay (+ 1 2))) (promise-expr p) ; => (+ 1 2) ``` ```{arl, include=FALSE} (define __pe (delay (+ 1 2))) (assert-equal '(+ 1 2) (promise-expr __pe)) ``` **Note:** Signals an error if p is not a promise. **See also:** [promise?](#promise-p), [force](#force), [delay](#delay) --- ## Environment Introspection {#section-environment-introspection} ### toplevel-env {#toplevel-env} Return the top-level engine environment where user definitions and standard library exports live. This is the environment used by eval_text and the REPL. Note that builtins-env sits between this environment and R's baseenv() in the parent chain. **Signature:** `(toplevel-env)` **Examples:** ```{arl} (environment? (toplevel-env)) ; => #t ``` ```{arl, include=FALSE} (assert-true (environment? (toplevel-env))) ``` **See also:** [current-env](#current-env), [builtins-env](#builtins-env) --- ### builtins-env {#builtins-env} Return the builtins environment that sits between the top-level engine environment and R's baseenv(). Contains core operators (=, +, *, <, etc.), module/macro registries, and environment commands. Module environments parent to this environment rather than to toplevel-env, which enforces that modules must explicitly import stdlib functions. **Signature:** `(builtins-env)` **Examples:** ```{arl} (environment? (builtins-env)) ; => #t ``` ```{arl, include=FALSE} (assert-true (environment? (builtins-env))) ``` **See also:** [toplevel-env](#toplevel-env), [current-env](#current-env) --- ### current-env {#current-env} Return the current Arl evaluation environment. **Signature:** `(current-env)` **Examples:** ```{arl} (environment? (current-env)) ; => #t ``` ```{arl, include=FALSE} (assert-true (environment? (current-env))) ``` **See also:** [toplevel-env](#toplevel-env), [builtins-env](#builtins-env) --- ## Module Introspection {#section-module-introspection} ### module-ref {#module-ref} Look up a symbol in a module or namespace. This is the desugared form of qualified access: `mod/sym` parses as `(module-ref mod sym)`. **Signature:** `(module-ref mod sym)` **Examples:** ```{arl} (import math) (module-ref math inc) ; same as math/inc ``` ```{arl, include=FALSE} (module __mr-mod (export __mr-x) (define __mr-x 99)) (import __mr-mod) (assert-equal 99 (module-ref __mr-mod __mr-x)) ``` **See also:** [import](#import), [module?](#module-p), [module-exports](#module-exports) --- ### module? {#module-p} Return #t if x is a module environment (registered in the module registry). **Signature:** `(module? x)` **Examples:** ```{arl} (import math) (module? math) ; => #t (module? 42) ; => #f ``` ```{arl, include=FALSE} (module __mp-mod (export __mp-a) (define __mp-a 1)) (import __mp-mod) (assert-true (module? __mp-mod)) (assert-false (module? 42)) ``` **See also:** [namespace?](#namespace-p), [module-exports](#module-exports), [module-name](#module-name) --- ### namespace? {#namespace-p} Return #t if x is a namespace node (created by importing a hierarchical module name like `a/b`). **Signature:** `(namespace? x)` **Examples:** ```{arl} (namespace? 42) ; => #f (namespace? "hello") ; => #f ``` ```{arl, include=FALSE} (assert-false (namespace? 42)) (assert-false (namespace? "hello")) ``` **See also:** [module?](#module-p), [module-ref](#module-ref) --- ### module-exports {#module-exports} Return the list of exported symbol names from a module. **Signature:** `(module-exports mod)` **Examples:** ```{arl} (import math) (module-exports math) ; => list of exported names ``` ```{arl, include=FALSE} (module __me-mod (export __me-x __me-y) (define __me-x 1) (define __me-y 2)) (import __me-mod) (define __me-exports (module-exports __me-mod)) (assert-true (list? __me-exports)) ``` **See also:** [module?](#module-p), [module-name](#module-name), [module-ref](#module-ref) --- ### module-name {#module-name} Return the canonical name string of a module. **Signature:** `(module-name mod)` **Examples:** ```{arl} (import math) (module-name math) ; => "math" ``` ```{arl, include=FALSE} (module __mn-mod (export __mn-a) (define __mn-a 1)) (import __mn-mod) (assert-equal "__mn-mod" (module-name __mn-mod)) ``` **See also:** [module?](#module-p), [module-exports](#module-exports) ---