--- title: "Standard Library: Higher-Order Functions" output: arl::arl_html_vignette pkgdown: as_is: true vignette: > %\VignetteIndexEntry{Standard Library: Higher-Order Functions} %\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).* ## Core Higher-Order Functions {#section-core-higher-order-functions} The fundamental building blocks for functional programming in Arl. These functions operate on lists and follow the convention of taking the function argument first, then the data argument. ### map {#map} Apply function to each element. With one list, maps fn over it. With multiple lists, maps fn over corresponding elements (like Scheme's map). **Signature:** `(map fn lst rest...)` **Parameters:** - **`fn`** — Function to apply to each element (or corresponding elements) - **`lst`** — First list to transform - **`rest`** — Additional lists for multi-list mapping **Examples:** ```{arl} (map (lambda (x) (* x 2)) (list 1 2 3)) ; => (2 4 6) (map + (list 1 2 3) (list 4 5 6)) ; => (5 7 9) ``` ```{arl, include=FALSE} (assert-equal (list 2 4 6) (map (lambda (x) (* x 2)) (list 1 2 3))) (assert-equal (list 5 7 9) (map + (list 1 2 3) (list 4 5 6))) ``` **See also:** [filter](#filter), [mapcat](#mapcat), [reduce](#reduce) --- ### mapcat {#mapcat} Map then concatenate results. Uses do.call(c, ...) for O(n) concatenation. **Signature:** `(mapcat fn lst)` **Parameters:** - **`fn`** — Function that returns a list for each element - **`lst`** — List to transform **Examples:** ```{arl} (mapcat (lambda (x) (list x (* x 10))) (list 1 2 3)) ; => (1 10 2 20 3 30) (mapcat (lambda (x) (list x x)) (list 1 2 3)) ; => (1 1 2 2 3 3) ``` ```{arl, include=FALSE} (assert-equal (list 1 10 2 20 3 30) (mapcat (lambda (x) (list x (* x 10))) (list 1 2 3))) ``` **See also:** [map](#map), [flatten](lang-list-seq.html#flatten) --- ### filter {#filter} Filter items by predicate. **Signature:** `(filter pred lst)` **Parameters:** - **`pred`** — Predicate function; elements where it returns #t are kept - **`lst`** — List to filter **Examples:** ```{arl} (filter (lambda (x) (> x 2)) (list 1 2 3 4 5)) ; => (3 4 5) (filter even? (list 1 2 3 4 5 6)) ; => (2 4 6) (filter string? (list 1 "a" 2 "b")) ; => ("a" "b") ``` ```{arl, include=FALSE} (assert-equal (list 3 4 5) (filter (lambda (x) (> x 2)) (list 1 2 3 4 5))) ``` **See also:** [remove](#remove), [take-while](lang-list-seq.html#take-while), [drop-while](lang-list-seq.html#drop-while) --- ### remove {#remove} Remove items where predicate is true. **Signature:** `(remove pred lst)` **Parameters:** - **`pred`** — Predicate function; elements where it returns #t are removed - **`lst`** — List to filter **Examples:** ```{arl} (remove even? (list 1 2 3 4 5 6)) ; => (1 3 5) (remove (lambda (x) (> x 3)) (list 1 2 3 4 5)) ; => (1 2 3) ``` ```{arl, include=FALSE} (assert-equal (list 1 3 5) (remove even? (list 1 2 3 4 5 6))) ``` **See also:** [filter](#filter) --- ### reduce {#reduce} Reduce list with function. **Signature:** `(reduce fn lst rest...)` **Parameters:** - **`fn`** — Binary function taking accumulator and current element - **`lst`** — List to reduce - **`rest`** — Optional initial accumulator value **Examples:** ```{arl} (reduce + (list 1 2 3 4)) ; => 10 (reduce * (list 1 2 3 4)) ; => 24 (reduce + (list 1 2 3) 100) ; => 106 (with initial value) (reduce string-append (list "a" "b" "c")) ; => "abc" ``` ```{arl, include=FALSE} (assert-equal 10 (reduce + (list 1 2 3 4))) (assert-equal 24 (reduce * (list 1 2 3 4))) (assert-equal 106 (reduce + (list 1 2 3) 100)) ``` **See also:** [foldl](#foldl), [foldr](#foldr), [map](#map) --- ### foldl {#foldl} Left fold alias for reduce. Applies fn as (fn acc elem). **Signature:** `(foldl fn lst rest...)` **Parameters:** - **`fn`** — Binary function taking accumulator and current element - **`lst`** — List to fold over - **`rest`** — Optional initial accumulator value **Examples:** ```{arl} (foldl + (list 1 2 3 4)) ; => 10 (foldl - (list 1 2 3) 10) ; => 4 (10 - 1 - 2 - 3) (foldl (lambda (acc x) (cons x acc)) (list 1 2 3) (list)) ; => (3 2 1) ``` ```{arl, include=FALSE} (assert-equal 10 (foldl + (list 1 2 3 4))) (assert-equal 4 (foldl - (list 1 2 3) 10)) (assert-equal (list 3 2 1) (foldl (lambda (acc x) (cons x acc)) (list 1 2 3) (list))) ``` **See also:** [foldr](#foldr), [reduce](#reduce) --- ### foldr {#foldr} Right fold. Applies fn as (fn elem acc). **Signature:** `(foldr fn lst rest...)` **Parameters:** - **`fn`** — Binary function taking current element and accumulator - **`lst`** — List to fold over from the right - **`rest`** — Optional initial accumulator value **Examples:** ```{arl} (foldr + (list 1 2 3 4)) ; => 10 (foldr - (list 1 2 3) 10) ; => -8 (1 - (2 - (3 - 10))) (foldr cons (list 1 2 3) (list)) ; => (1 2 3) (preserves order) ``` ```{arl, include=FALSE} (assert-equal 10 (foldr + (list 1 2 3 4))) (assert-equal -8 (foldr - (list 1 2 3) 10)) (assert-equal (list 1 2 3) (foldr cons (list 1 2 3) (list))) ``` **See also:** [foldl](#foldl), [reduce](#reduce) --- ### every? {#every-p} Return #t if predicate true for all items. **Signature:** `(every? pred lst)` **Parameters:** - **`pred`** — Predicate function to test each element - **`lst`** — List to check **Examples:** ```{arl} (every? positive? (list 1 2 3)) ; => #t (every? even? (list 2 4 6)) ; => #t (every? even? (list 2 3 6)) ; => #f (every? string? (list "a" "b" "c")) ; => #t ``` ```{arl, include=FALSE} (assert-true (every? positive? (list 1 2 3))) (assert-false (every? even? (list 2 3 6))) ``` **See also:** [any?](#any-p), [filter](#filter) --- ### any? {#any-p} Return #t if predicate true for any item. **Signature:** `(any? pred lst)` **Parameters:** - **`pred`** — Predicate function to test each element - **`lst`** — List to check **Examples:** ```{arl} (any? even? (list 1 3 4 5)) ; => #t (any? negative? (list 1 2 3)) ; => #f (any? string? (list 1 "a" 2)) ; => #t ``` ```{arl, include=FALSE} (assert-true (any? even? (list 1 3 4 5))) (assert-false (any? negative? (list 1 2 3))) ``` **See also:** [every?](#every-p), [filter](#filter) --- ### complement {#complement} Negate predicate. **Signature:** `(complement pred)` **Parameters:** - **`pred`** — Predicate function to negate **Examples:** ```{arl} (define not-even? (complement even?)) (not-even? 3) ; => #t (not-even? 4) ; => #f (filter (complement null?) (list 1 #nil 2 #nil 3)) ; => (1 2 3) ``` ```{arl, include=FALSE} (assert-true ((complement even?) 3)) (assert-false ((complement even?) 4)) ``` **See also:** [not](lang-core.html#not), [filter](#filter) --- ### compose {#compose} Compose two functions. **Signature:** `(compose f g)` **Parameters:** - **`f`** — Outer function (applied second) - **`g`** — Inner function (applied first) **Examples:** ```{arl} (define add1-then-double (compose (lambda (x) (* x 2)) (lambda (x) (+ x 1)))) (add1-then-double 3) ; => 8 ((3+1)*2) (define abs-sum (compose abs +)) (abs-sum -3 -4) ; => 7 ``` ```{arl, include=FALSE} (assert-equal 8 ((compose (lambda (x) (* x 2)) (lambda (x) (+ x 1))) 3)) ``` **See also:** [partial](#partial) --- ### partial {#partial} Partially apply function. **Signature:** `(partial fn captured...)` **Parameters:** - **`fn`** — Function to partially apply - **`captured`** — Arguments to bind to fn's first positions **Examples:** ```{arl} (define add5 (partial + 5)) (add5 3) ; => 8 (define greet (partial string-append "Hello, ")) (greet "world") ; => "Hello, world" ``` ```{arl, include=FALSE} (assert-equal 8 ((partial + 5) 3)) ``` **See also:** [compose](#compose) --- ## Advanced Functional Programming {#section-advanced-functional-programming} Higher-order combinators for advanced functional patterns including currying, juxtaposition, memoization, and iteration. ### curry {#curry} Curry a function - enables partial application with optional initial arguments. **Signature:** `(curry fn initial-args...)` **Parameters:** - **`fn`** — Function to curry (must have fixed arity) - **`initial-args`** — Optional arguments to apply immediately **Examples:** ```{arl} (define add (curry (lambda (a b) (+ a b)))) (define add5 (add 5)) (add5 3) ; => 8 (define multiply (curry (lambda (a b) (* a b)))) ((multiply 3) 4) ; => 12 ``` ```{arl, include=FALSE} (assert-equal 8 ((curry (lambda (a b) (+ a b)) 5) 3)) ``` **See also:** [partial](#partial) --- ### juxt {#juxt} Juxtaposition - apply multiple functions to same args, return list of results. **Signature:** `(juxt fns...)` **Parameters:** - **`fns`** — Functions to apply to the arguments **Examples:** ```{arl} (define stats (juxt min max mean)) (stats (c 1 2 3 4 5)) ; => (1 5 3) (define first-and-last (juxt car last)) (first-and-last (list 1 2 3)) ; => (1 3) ``` ```{arl, include=FALSE} (assert-equal (list 1 5 3) ((juxt min max mean) (c 1 2 3 4 5))) (assert-equal (list 1 3) ((juxt car last) (list 1 2 3))) ``` **See also:** [map](#map), [compose](#compose) --- ### constantly {#constantly} Return a function that always returns the given value. **Signature:** `(constantly value)` **Parameters:** - **`value`** — Value to return regardless of arguments **Examples:** ```{arl} (define always-42 (constantly 42)) (always-42) ; => 42 (always-42 "ignored" "args") ; => 42 (map (constantly 0) (list 1 2 3)) ; => (0 0 0) ``` ```{arl, include=FALSE} (assert-equal 42 ((constantly 42))) (assert-equal (list 0 0 0) (map (constantly 0) (list 1 2 3))) ``` --- ### iterate {#iterate} Apply function n times to initial value. **Signature:** `(iterate fn n init)` **Parameters:** - **`fn`** — Unary function to apply repeatedly - **`n`** — Number of times to apply fn - **`init`** — Starting value **Examples:** ```{arl} (iterate (lambda (x) (* x 2)) 5 1) ; => 32 (1 -> 2 -> 4 -> 8 -> 16 -> 32) (iterate inc 3 0) ; => 3 (0 -> 1 -> 2 -> 3) (iterate (lambda (x) (* x x)) 2 2) ; => 16 (2 -> 4 -> 16) ``` ```{arl, include=FALSE} (assert-equal 32 (iterate (lambda (x) (* x 2)) 5 1)) (assert-equal 3 (iterate inc 3 0)) (assert-equal 16 (iterate (lambda (x) (* x x)) 2 2)) ``` **See also:** [iterate-until](#iterate-until), [reduce](#reduce) --- ### iterate-until {#iterate-until} Apply function starting from init, collecting values until predicate becomes true. Includes all values where predicate is false, stops when next value would satisfy predicate. **Signature:** `(iterate-until fn init pred)` **Parameters:** - **`fn`** — Unary function to apply repeatedly - **`init`** — Starting value - **`pred`** — Predicate that signals when to stop collecting **Examples:** ```{arl} (iterate-until (lambda (x) (* x 2)) 1 (lambda (x) (> x 100))) ; => (1 2 4 8 16 32 64) (stops before 128 which exceeds 100) (iterate-until inc 0 (lambda (x) (>= x 5))) ; => (0 1 2 3 4) ``` ```{arl, include=FALSE} (assert-equal (list 1 2 4 8 16 32 64) (iterate-until (lambda (x) (* x 2)) 1 (lambda (x) (> x 100)))) (assert-equal (list 0 1 2 3 4) (iterate-until inc 0 (lambda (x) (>= x 5)))) ``` **See also:** [iterate](#iterate), [take-while](lang-list-seq.html#take-while) --- ### memoize {#memoize} Memoize function - cache results for previously seen arguments. **Signature:** `(memoize fn)` **Parameters:** - **`fn`** — Function whose results to cache by arguments **Examples:** ```{arl} (define slow-fib (lambda (n) (if (< n 2) n (+ (slow-fib (- n 1)) (slow-fib (- n 2)))))) (define fast-fib (memoize slow-fib)) (fast-fib 10) ; => 55 (fast-fib 10) ; => 55 (cached, instant) ``` ```{arl, include=FALSE} (assert-equal 4 ((memoize (lambda (x) (* x x))) 2)) (assert-equal 4 ((memoize (lambda (x) (* x x))) 2)) ``` --- ## Iteration and Counting {#section-iteration-and-counting} Functions for side-effecting iteration and counting over sequences. ### for-each {#for-each} Apply function to each element for side effects. Returns #nil. Supports multiple lists like multi-list map. **Signature:** `(for-each fn lst rest...)` **Parameters:** - **`fn`** — Function to apply for side effects - **`lst`** — First list - **`rest`** — Additional lists for multi-list iteration **Examples:** ```{arl} (for-each print '(1 2 3)) ; prints 1 2 3, returns #nil ``` ```{arl, include=FALSE} (assert-equal #nil (for-each (lambda (x) x) (list 1 2 3))) ``` **See also:** [map](#map) --- ### count {#count} Count elements matching predicate. **Signature:** `(count pred lst)` **Parameters:** - **`pred`** — Predicate function to test each element - **`lst`** — List to count matching elements in **Examples:** ```{arl} (count even? (list 1 2 3 4)) ; => 2 (count even? (list)) ; => 0 ``` ```{arl, include=FALSE} (assert-equal 2 (count even? (list 1 2 3 4))) (assert-equal 0 (count even? (list))) ``` **See also:** [filter](#filter), [every?](#every-p), [any?](#any-p) --- ### map-indexed {#map-indexed} Map with index. Calls (fn index element) for each element, with 0-based indices. **Signature:** `(map-indexed fn lst)` **Parameters:** - **`fn`** — Function taking index and element - **`lst`** — List to map over **Examples:** ```{arl} (map-indexed list '(a b c)) ; => ((0 a) (1 b) (2 c)) ``` ```{arl, include=FALSE} (assert-equal (list (list 0 'a) (list 1 'b) (list 2 'c)) (map-indexed list (list 'a 'b 'c))) ``` **See also:** [map](#map) --- ### group-by {#group-by} Group elements by key function. Returns a dict mapping each key (as string) to a list of matching elements. **Signature:** `(group-by key-fn lst)` **Parameters:** - **`key-fn`** — Function to compute the grouping key for each element - **`lst`** — List to group **Examples:** ```{arl} (group-by even? '(1 2 3 4)) ; => dict with TRUE->(2 4), FALSE->(1 3) ``` **See also:** [frequencies](#frequencies), [filter](#filter) --- ### frequencies {#frequencies} Count occurrences of each element. Returns a dict mapping each element (as string) to its count. **Signature:** `(frequencies lst)` **Parameters:** - **`lst`** — List to count element frequencies in **Examples:** ```{arl} (frequencies '(a b a c b a)) ; => dict with a->3 b->2 c->1 ``` **See also:** [group-by](#group-by), [count](#count) --- ## Logical Operations {#section-logical-operations} Core logical operations for Arl. Note that `and` and `or` are compiler special forms (not functions) with short-circuit evaluation, so they are not part of this module. ### not {#not} Logical negation with Arl truthiness. **Signature:** `(not x)` **Parameters:** - **`x`** — Value to negate **Examples:** ```{arl} (not #t) ; => #f (not #f) ; => #t (not 0) ; => #t (0 is falsy) (not 1) ; => #f (non-zero is truthy) (not #nil) ; => #t (NULL is falsy) (not "hello") ; => #f (non-empty values are truthy) ``` ```{arl, include=FALSE} (assert-false (not #t)) (assert-true (not #f)) (assert-true (not 0)) (assert-false (not 1)) (assert-true (not #nil)) (assert-false (not "hello")) ``` **Note:** Arl follows Scheme-like truthiness: #f/FALSE, #nil/NULL, and 0 are falsy. Everything else is truthy. This differs from R where only FALSE and NULL are falsy. **See also:** [xor](#xor), [and](lang-core.html#and), [or](lang-core.html#or) (special forms) --- ### xor {#xor} Logical exclusive OR with Arl truthiness. **Signature:** `(xor a b)` **Parameters:** - **`a`** — First value - **`b`** — Second value **Examples:** ```{arl} (xor #t #f) ; => #t (xor #f #t) ; => #t (xor #t #t) ; => #f (xor #f #f) ; => #f (xor 1 0) ; => #t (1 is truthy, 0 is falsy) (xor 1 2) ; => #f (both truthy) ``` ```{arl, include=FALSE} (assert-true (xor #t #f)) (assert-true (xor #f #t)) (assert-false (xor #t #t)) (assert-false (xor #f #f)) (assert-true (xor 1 0)) (assert-false (xor 1 2)) ``` **Note:** Exclusive OR: returns #t when exactly one argument is truthy, #f when both are truthy or both are falsy. **See also:** [not](lang-core.html#not), [and](lang-core.html#and), [or](lang-core.html#or) (special forms) ---