Functional utilities

To use the bindings from this module:

(import :std/misc/func)

Collection of mixed purpose higher-order functions.

always

(always val)            -> procedure
(always proc [arg ...]) -> procedure

  val     := value that should always be returned
  proc    := procedure that should always be called
  arg ... := optional arguments that will be passed to proc

Creates a lambda which returns the same val or calls always the same proc with the same optional args.

Examples:

> (def fn (always 5))
> (list (fn) (fn) (fn)))
(5 5 5)

> (def fn (always random-integer 10))
> [(fn) (fn) (fn)]
(4 3 8)

repeat

(repeat val n)            -> list
(repeat proc n [arg ...]) -> list

  val     := value that should be repeated
  proc    := proc that should be called n times
  n       := exact number, repetitions
  arg ... := optional arguments that will be passed to proc

Repeat val or call proc with the optional args n times and return the result as list. n is expected to be an exact number.

Examples:

> (repeat 2 5)
(2 2 2 2 2)

> (repeat (lambda () 10) 3)
(10 10 10)

> (repeat random-integer 3 10)
(8 3 5)

compose1

(compose1 f1 f ...) -> procedure

  f1, f ... := procedures

Composes a sequence of unary functions; per the mathematical function composition the value flows right-to-left.

rcompose1

(rcompose1 f1 f ...) -> procedure

  f1, f ... := procedures

Like compose1, but the value flows left-to-right.

compose

(compose f1 f ...) -> procedure

  f1, f ... := procedures

Like compose1, but the composed function accepts multiple arguments.

Note: If you are composing unary functions, use compose1, as it avoids allocation from capturing arguments for apply.

rcompose

(rcompose f1 f ...) -> procedure

  f1, f ... := procedures

Like compose, but the values flow left-to-right.

compose/values

(compose/values f1 f ...) -> procedure

  f1, f ... := procedures

Like compose, but the composed function accepts multiple arguments and all functions can return multiple values, which are then applied as arguments to the next function in the sequence.

rcompose/values

(rcompose/values f1 f ...) -> procedure

  f1, f ... := procedures

Like compose/values, but the values flow left-to-right.

Functional composition macros

(@compose1 f1 f ...)
(@compose f1 f ...)
(@compose/values f1 f ...)
(@rcompose1 f1 f ...)
(@rcompose f1 f ...)
(@rcompose/values f1 f ...)

These are macro versions of the functional composition operators; they generate significantly more efficient code and allow the optimizer to see through the composition.

every-of

(every-of preds v [test: equal?]) -> boolean

  preds := list of predicates or values
  v     := value to compare with predicates
  test  := optional, if preds contains a value, test is used for comparison

every-of returns #t if all predicates match. If preds contains a non-predicate, it is transformed into one using equal? as test if not overridden by the test: keyword.

Examples:

> (every-of [number? fixnum?] 2)
#t

> (every-of [] 1)
#t

> (every-of [number? 10] 10 test: =)
#t

any-of

(any-of preds v [test: equal?]) -> boolean

  preds := list of predicates or values
  v     := value to compare with predicates
  test  := optional, if preds contains a value, test is used for comparison

any-of returns #t if one predicate matches. If preds contains a non-predicate, it is transformed into one using equal? as test if not overridden by the test: keyword.

Examples:

> (any-of [number? symbol?] 'a)
#t

> (any-of [] 1)
#f

> (any-of ['a 'b] 'b test: eq?)
#t

pred-limit

(pred-limit pred limit) -> procedure

  pred  := predicate
  limit := number of times pred is allowed to return a truthy value

pred-limit returns a predicate which returns a truthy value only limit times, if limit is not false.

Examples:

> (filter (pred-limit even? 1) [1 2 3 4 5 6])
(2)

(def (myfilter pred list (limit #f))
  (filter (pred-limit pred limit) list))

> (myfilter even? [1 2 3 4 5 6])
(2 4 6)

> (myfilter even? [1 2 3 4 5 6] 2)
(2 4)

> (myfilter even? [1 2 3 4 5 6] 0)
()

pred-sequence

(pred-sequence lst [limit = #f]) -> procedure

  lst   := proper or circular list
  limit := optional, return #t only limit times

pred-sequence returns a predicate which returns #t on the last element of a matching sequence. The list elements are compared using equal?. #t is returned limit times, if limit is not #f.

Examples:

> (import (only-in :std/srfi/13 string-count))
> (string-count "ab_ab" (pred-sequence [#\a #\b]))
2

> (let (fn (pred-sequence [1 2]))
    (fn 0)  ; #f
    (fn 1)  ; #f
    (fn 2)) ; #t

pred-and

(pred-and pred) -> procedure

  pred  := predicate

pred-and returns #t when every pred invocation returned a truethy value.

Examples:

> (let (fn (pred-and number?))
    (fn 10)
    (fn 20))
#t

pred-or

(pred-or pred) -> procedure

  pred  := predicate

pred-or returns #t when any pred invocation returned a truethy value.

Examples:

> (let (fn (pred-or number?))
    (fn 'a)
    (fn 20)
    (fn "b"))
#t

pred-every-of

(pred-every-of preds [test: equal?]) -> procedure

  preds := list of predicates or values
  test  := optional, if preds contains a value, test is used for comparison

pred-every-of returns a predicate which returns #t if all predicates match. If preds contains a non-predicate, it is transformed into one using equal? as test if not overridden by the test: keyword.

Examples:

> (filter (pred-every-of [number? fixnum?]) [1 'a 2.0 "b" 30])
(1 30)

pred-any-of

(pred-any-of preds [test: equal?]) -> procedure

  preds := list of predicates or values
  test  := optional, if preds contains a value, test is used for comparison

pred-any-of returns a predicate which returns #t if one predicate matches. If preds contains a non-predicate, it is transformed into one using equal? as test if not overridden by the test: keyword.

Examples:

> (filter (pred-any-of [number? fixnum? "b"]) [1 'a 2.0 "b" 30])
(1 2. "b" 30)

> (import :std/sugar)
> (def files (directory-files))

> (filter (is path-extension (pred-any-of [".jpg" ".jpeg" ".png"])) files)
("xkcd_lisp.jpg" "logo.png")