On this page:
5.1 Syntax
lambda/  function
lambda/  f
λ/  f
define/  function
define/  f
lambda.
λ.
app
5.2 Representation
5.3 Utilities
function-cons
function-null
function-flat-arguments
apply/  steps
compose
curry
curryr
uncurry
partial
partial/  template
conjoin
&&
disjoin
||
negate
!!
unthunk
if-f
true.
false.
arg
flip
flip$
flip*
lift
pack
call
5.4 Types
5.4.1 Functions and Composition
function
monoid
make-function
f
make-threading-function
f>
5.4.2 Function Application
gen:  application-scheme
application-scheme?
pass
flat-arguments
handle-failure
curried-arguments
empty-curried-arguments
template-arguments

5 Functional Primitives

 (require relation/function) package: relation

Elementary types and utilities to simplify the use and manipulation of functions.

This module provides general-purpose utilities to support programming in the functional style. As part of its operation, this module defines and provides a "rich" function type intended as a drop-in alternative to built-in Racket functions. This function type is usually no different from using normal functions, but as a higher-level entity, it provides greater visibility of the make-up of the function, allowing more flexibility in customizing the nature of composition, supporting natural semantics when used with standard sequence utilities, and more seamless use of currying and partial application.

    5.1 Syntax

    5.2 Representation

    5.3 Utilities

    5.4 Types

      5.4.1 Functions and Composition

      5.4.2 Function Application

5.1 Syntax

syntax

(lambda/function kw-formals body ...)

syntax

(lambda/f kw-formals body ...)

syntax

(λ/f kw-formals body ...)

Identical to lambda except that it produces a function rather than a primitive Racket function. lambda/f and λ/f are aliases for lambda/function.

syntax

(define/function (id kw-formals) body ...)

syntax

(define/f kw-formals body ...)

Identical to the function form of define except that it produces a function rather than a primitive Racket function. define/f is an alias for define/function.

syntax

(lambda. kw-formals ... -> body ...)

syntax

(λ. kw-formals ... -> body ...)

A lightweight way to define anonymous functions (lambdas) inspired by Haskell’s syntax for lambdas. Equivalent to lambda/f except that it does not support a rest argument, so it is best suited for simple cases like inline lambdas, rather than more complex cases such as a prop:procedure specification. In any case, if a rest argument is needed, use lambda/f directly.

Either -> or may be used as the syntactic separator between the arguments and the body of the function.

Examples:
> ((λ. x -> (sqr x)) 5)

25

> (map ((λ. x y -> (expt x y)) 2) (range 10))

'(1 2 4 8 16 32 64 128 256 512)

> ((λ. -> 10))

10

> ((λ. x y -> (+ x y)) 5 10)

15

> ((λ. x y #:key [key #f] -> (= #:key key x y)) 5 "5")

#f

> ((λ. x y #:key [key #f] -> (= #:key key x y)) #:key ->string 5 "5")

#t

syntax

(app fn template-args ...)

Syntactic sugar on the partial/template interface, inspired by and greatly resembling Fancy App: Scala-Style Magic Lambdas, this enables applying a function to arguments with reference to a template specified in advance that indicates the expected arguments and their positions.

Examples:
> (app + 2 _)

'(λ (2 _) (.. #<procedure:+>))

> ((app + 2 _) 3)

5

> (map (app * 2 _) (list 1 2 3))

'(2 4 6)

> ((app string-append _ "-" _) "seam" "less")

"seam-less"

> (app = #:key string-upcase "apple" _)

'(λ ("apple" _ #:key #<procedure:string-upcase>) (.. #<procedure:=>))

> ((app = #:key string-upcase _ "apple") "APPLE")

#t

> ((app = #:key _ "apple" _) "APPLE")

Missing keyword argument in template!

keyword: #:key

> ((app = #:key _ "apple" _) #:key string-upcase "APPLE")

#t

5.2 Representation

The printed representation of a function has some features worthy of note. Let’s look at an example.

> (f add1 sqr)

'(λ (_) (.. #<procedure:add1> #<procedure:sqr>))

The first thing to note is that the printed representation is almost itself valid code to reproduce the function it represents. A prominent maxim of programming in the functional style is to write complex functions in terms of small, simple functions that can be composed together. The transparency of this representation is intended to support this habit, by enabling the makeup of such functions, whether simple or complex, to be easily scrutinized and manipulated. Specific clues encoded in the representation are as follows:
(λ (args _) ...)
In general, the arguments portion of the representation indicates the application scheme. Here, it indicates that the function is left-curried (the default), while
(λ (_ args) ...)
indicates that it is right-curried (the _ indicates where fresh arguments will be placed in relation to the existing arguments). If arguments have been supplied on both sides, either via currying or a template, the _ will indicate the argument position(s) between the already-supplied arguments.
(.. fn ...)
indicates that the method of composition is the usual one, i.e. compose,
(&& fn ...)
means the method of composition is conjoin,
(|| fn ...)
means disjoin, and
(?? fn ...)
indicates that the method of composition is not a standard one but a custom monoid.

More examples:
> (f add1 sqr)

'(λ (_) (.. #<procedure:add1> #<procedure:sqr>))

> ((f expt) 2)

'(λ (2 _) (.. #<procedure:expt>))

> (partial expt 2)

'(λ (arguments 2) (.. #<procedure:expt>))

> (curry = #:key string-upcase "apple")

'(λ ("apple" _) (.. #<procedure:=>))

> (curryr member? (list 1 2 3))

'(λ (_ (1 2 3)) (.. #<procedure:member?>))

> (curryr (curry string-append "ichi") "san")

'(λ ("ichi" _ "san") (.. #<procedure:string-append>))

> (app string-append "ichi" _ "san" _ "go")

'(λ ("ichi" _ "san" _ "go") (.. #<procedure:string-append>))

> (&& positive? odd?)

'(λ (_) (&& #<procedure:positive?> #<procedure:odd?>))

> (|| positive? odd?)

'(λ (_) (|| #<procedure:positive?> #<procedure:odd?>))

> (f #:compose-with (monoid (λ (f g) g) values) add1 sub1)

'(λ (_) (?? #<procedure:add1> #<procedure:sub1>))

5.3 Utilities

procedure

(function-cons v w)  function?

  v : procedure?
  w : function?

procedure

(function-null [#:compose-with composer    
  #:curry-on side])  function?
  composer : monoid? = (monoid compose values)
  side : symbol? = 'left
Constructors for the function type analogous to cons and null for lists. function-null also serves as the identity value for composition.

Examples:
> (function-cons add1 (f ->number))

'(λ (_) (.. #<procedure:add1> #<procedure:->number>))

> ((function-cons add1 (function-null)) 3)

4

procedure

(function-flat-arguments g)  arguments?

  g : function?
Returns an arguments structure representing the arguments that parameterize (i.e. have already been passed to) the function g.

Examples:
> (function-flat-arguments (curry + 1 2 3))

(arguments 1 2 3)

> (function-flat-arguments (curry = #:key string-upcase "apple"))

(arguments "apple" #:key #<procedure:string-upcase>)

> (function-flat-arguments (curry (curryr (curry string-append "hello") "friend") "there"))

(arguments "hello" "there" "friend")

procedure

(apply/steps g v ... lst #:<kw> kw-arg ...)  sequence?

  g : function?
  v : any/c
  lst : list?
  kw-arg : any/c
Similar to apply, but yields a sequence corresponding to the values at each stage of application of the function g.

Examples:
> (->list (apply/steps (f add1 sub1 add1) (list 3)))

'(4 3 4)

> (->list (apply/steps (f> ->number add1 ->string) (list "1")))

'(1 2 "2")

procedure

(compose g ...)  function?

  g : procedure?
Analogous to compose, but yields a function rather than a primitive Racket procedure. In general, the composition is performed "naively" by simply wrapping the component functions with a new function. In the common case where the component functions have identical composition and application schemes, however, the functions are composed "at the same level," preserving the composition method in the resulting composed function, whether it is the usual function composition or something else.

In principle, composition of functions could be formally simplified in certain additional cases including homogeneous or trivial application schemes. This "runtime compilation" would have no impact on the behavior of the resulting function, however, and is left for future consideration.

Examples:
> (compose ->string +)

'(λ (_) (.. #<procedure:->string> #<procedure:+>))

> (compose ->string (f +))

'(λ (_) (.. #<procedure:->string> #<procedure:+>))

> (compose (f ->string) +)

'(λ (_) (.. #<procedure:->string> #<procedure:+>))

> (compose (f ->string) (f +))

'(λ (_) (.. #<procedure:->string> #<procedure:+>))

> (compose odd? (conjoin positive? integer?))

'(λ (_)

   (..

    (λ (_) (.. #<procedure:odd?>))

    (λ (_) (&& #<procedure:positive?> #<procedure:integer?>))))

> (compose (conjoin odd?) (conjoin positive? integer?))

'(λ (_) (&& #<procedure:odd?> #<procedure:positive?> #<procedure:integer?>))

> (compose ->string (curry + 2))

'(λ (_) (.. (λ (_) (.. #<procedure:->string>)) (λ (2 _) (.. #<procedure:+>))))

procedure

(curry g v ...)  function?

  g : procedure?
  v : any/c

procedure

(curryr g v ...)  function?

  g : procedure?
  v : any/c
Analogous to curry and curryr, but these yield a function rather than a primitive Racket procedure. Since functions are inherently curried, explicitly invoking curry is usually not necessary, but can be useful in cases where evaluation needs to be delayed until additional arguments are received. An explicit call to curry will not immediately evaluate to a result even if sufficient arguments have been provided for the invocation to produce a result.

Examples:
> (curry + 2)

'(λ (2 _) (.. #<procedure:+>))

> (curry + 2 3)

'(λ (2 3 _) (.. #<procedure:+>))

> ((curryr < 5) 3)

#t

> (curry (curryr (curry string-append "ichi") "san") "ni")

'(λ ("ichi" "ni" _ "san") (.. #<procedure:string-append>))

> ((curryr (curry string-append "ichi" "-") "-" "san") "ni")

"ichi-ni-san"

procedure

(uncurry g)  function?

  g : procedure?
Convert a curried function g accepting single arguments in succession to an equivalent one accepting an arbitrary number of arguments at once. This is typically not needed since both curry as well as Racket’s built-in currying interfaces support partial application with an arbitrary number of arguments, but it can be useful with naively curried functions not created using one of these interfaces.

Examples:
> (define (curried-add-3 x)
    (λ (y)
      (λ (z)
        (+ x y z))))
> (curried-add-3 1 4 7)

curried-add-3: arity mismatch;

 the expected number of arguments does not match the given

number

  expected: 1

  given: 3

> ((uncurry curried-add-3) 1 4 7)

12

procedure

(partial g v ...)  function?

  g : procedure?
  v : any/c
Partially apply the function g using the provided arguments. The result is a function with a flat set of these pre-supplied arguments which must be invoked with all of the remaining expected arguments when the time comes, i.e. it is not curried.

Examples:
> (partial + 2)

'(λ (arguments 2) (.. #<procedure:+>))

> ((partial + 2) 3 4)

9

procedure

(partial/template g v ...)  function?

  g : procedure?
  v : maybe/c
Partially apply the function g using the specified argument template. This template takes the form of a series of optional values, provided directly, either as positional or keyword arguments. The result is a function that expects precisely those arguments that are indicated as "missing" in the template. Note that this function is not curried. Typically this would be used via the convenient app syntax, rather than directly.

Examples:
> (partial/template = #:key (just string-upcase) (just "apple") nothing)

'(λ ("apple" _ #:key #<procedure:string-upcase>) (.. #<procedure:=>))

> ((partial/template = #:key (just string-upcase) nothing (just "apple")) "APPLE")

#t

> ((partial/template = #:key nothing (just "apple") nothing) #:key string-upcase "APPLE")

#t

procedure

(conjoin g ...)  function?

  g : procedure?

procedure

(&& g ...)  function?

  g : procedure?
Analogous to conjoin, this yields a function whose composition method is conjoin rather than compose. && is provided as a convenient alias, following the convention in The Algebraic Racket Collection.

Examples:
> (&& positive? integer?)

'(λ (_) (&& #<procedure:positive?> #<procedure:integer?>))

> ((&& positive? integer?) -5)

#f

> ((&& positive? integer?) 5.3)

#f

> ((&& positive? integer?) 5)

#t

procedure

(disjoin g ...)  function?

  g : procedure?

procedure

(|| g ...)  function?

  g : procedure?
Analogous to disjoin, this yields a function whose composition method is disjoin rather than compose. || is provided as a convenient alias, following the convention in The Algebraic Racket Collection.

Examples:
> (|| positive? integer?)

'(λ (_) (|| #<procedure:positive?> #<procedure:integer?>))

> ((|| positive? integer?) -5)

#t

> ((|| positive? integer?) 5.3)

#t

> ((|| positive? integer?) 5)

#t

> ((|| positive? integer?) -5.3)

#f

procedure

(negate g)  function?

  g : procedure?

procedure

(!! g)  function?

  g : procedure?
Analogous to negate, this yields a function whose result is the boolean negation of the result of applying g.

Examples:
> (!! positive?)

'(λ (_) (.. #<procedure:not> #<procedure:positive?>))

> ((!! positive?) -5)

#t

> ((!! positive?) 5)

#f

procedure

(unthunk g v ...)  procedure?

  g : procedure?
  v : any/c
Converts a procedure accepting no arguments to one accepting an arbitrary number of arguments (which are all ignored upon invocation). In other words, this converts a thunk into a thunk*.

Examples:
> (define gen (unthunk (sequence->generator '(1 2 3))))
> (gen "some")

1

> (gen 'ignored)

2

> (gen "arguments" 'a 'b 42)

3

procedure

(if-f pred f g)  procedure?

  pred : (-> any/c boolean?)
  f : procedure?
  g : procedure?
Analogous to if, checks the predicate pred against an input value and applies either f or g to it depending on the result.

Examples:
> ((if-f positive? add1 sub1) 3)

4

> (map (if-f positive? add1 sub1) (list 3 -3))

'(4 -4)

procedure

(true. v)  boolean?

  v : any

procedure

(false. v)  boolean?

  v : any
true. is an agreeable function that always returns #t, while false. is a contrarian that always returns #f. Both accept an arbitrary number of arguments (disregarding all of them).

Examples:
> (true.)

#t

> (true. 3 1 #:key 'hi)

#t

> (false.)

#f

> (false. 3 1 #:key 'hi)

#f

procedure

(arg n)  procedure?

  n : exact-nonnegative-integer?
Produces a function whose value is simply its nth argument.

Examples:
> ((arg 0) "hi" "there")

"hi"

> ((arg 2) "hi" "there" 'abc 'pqr)

'abc

> ((arg 3) -2 -1 0 1 2 3)

1

> (apply (arg 3) (range 10))

3

> (regexp-replace* #rx"\\[\\[(cat|dog)\\]\\]"
                   "The [[cat]] and the [[dog]] in the hat."
                   (arg 1))

"The cat and the dog in the hat."

procedure

(flip g)  procedure?

  g : procedure?

procedure

(flip$ g)  procedure?

  g : procedure?

procedure

(flip* g)  procedure?

  g : procedure?
flip yields a function identical to the one passed in, but with the first two argument positions swapped, flip$ passes the first argument in the last argument position (leaving other arguments in the original relative positions), while flip* reverses the entire list of arguments.

Examples:
> ((flip string-append) "my" "hello" "friend")

"hellomyfriend"

> ((flip$ string-append) "friend" "hello" "my")

"hellomyfriend"

> ((flip* string-append) "friend" "my" "hello")

"hellomyfriend"

procedure

(lift g)  procedure?

  g : procedure?
"Lifts" a function operating on ordinary values to a function operating on a functor (for instance, a list of such values) in the natural way. This is a thin wrapper around map, and may lend clarity in cases where you want to derive such a function but not necessarily apply it immediately.

Examples:
> (define list-add1 (lift add1))
> (->list (list-add1 (list 1 2 3)))

'(2 3 4)

> (->list ((lift ->string) (list 1 2 3)))

'("1" "2" "3")

> ((lift add1) (just 3))

(just 4)

procedure

(pack g v ...)  procedure?

  g : procedure?
  v : any/c
"Pack" the provided arguments into a list and map them individually under g. While map allows a function operating on individual arguments to operate on such arguments provided as a list, pack analogously allows the function to operate on such arguments provided directly as multiple arguments.

Examples:
> (pack sqr 1 2 3 4)

'(1 4 9 16)

> (pack ->string 1 2 3)

'("1" "2" "3")

procedure

(call g v ...)  procedure?

  g : procedure?
  v : any/c
Reprovided from call. This simply makes standard function invocation available as a function, for use in cases where we cannot directly (i.e. syntactically) invoke the function. This function is in some respects similar to the $ operator in Haskell.

Examples:
> (call + 1 2 3 4)

10

> (call = #:key string-upcase "Apple" "APPLE")

#t

> (map call (list add1 sqr) (list 2 3))

'(3 9)

5.4 Types

5.4.1 Functions and Composition

struct

(struct function (components composer applier chirality))

  components : list?
  composer : monoid?
  applier : application-scheme?
  chirality : symbol?
A type that represents any procedure, whether elementary or composed. It is curried by default, meaning that partially supplying arguments results in a new function parametrized by these already-provided arguments.
  • components - A list of functions that comprise this one.

  • composer - The definition of composition for this function. By default (when constructed using make-function), this is the usual function composition, i.e. compose together with values as the identity.

  • applier - The definition of application for this function. By default, this is curried partial application, meaning the function takes an arbitrary number of positional and keyword arguments at a time and evaluates to a result when sufficient arguments have been provided, or to a new function accepting more arguments otherwise. Other possible application schemes include uncurried with optional partial application (a minimal generalization of the default behavior for normal Racket functions) and template-based partial application (resembling the application behavior in Fancy App: Scala-Style Magic Lambdas).

  • chirality - The direction (left-to-right or right-to-left) in which provided arguments will be incorporated.

struct

(struct monoid (f id))

  f : (-> procedure? procedure? procedure?)
  id : procedure?
A composer of functions, generalizing "normal" function composition to support any definition of composition. Any suitable notion of function composition (and hence instances of this monoid type) must include:

procedure

(make-function [#:compose-with composer    
  #:apply-with applier]    
  g ...)  function?
  composer : monoid? = (monoid compose values)
  applier : application-scheme? = empty-curried-arguments
  g : procedure?

procedure

(f [#:compose-with composer    
  #:apply-with applier]    
  g ...)  function?
  composer : monoid? = (monoid compose values)
  applier : application-scheme? = empty-curried-arguments
  g : procedure?

procedure

(make-threading-function [#:compose-with composer    
  #:apply-with applier]    
  g ...)  function?
  composer : monoid? = (monoid compose values)
  applier : application-scheme? = empty-curried-arguments
  g : procedure?

procedure

(f> [#:compose-with composer    
  #:apply-with applier]    
  g ...)  function?
  composer : monoid? = (monoid compose values)
  applier : application-scheme? = empty-curried-arguments
  g : procedure?
A constructor for creating functions from other functions. f functions compose right-to-left (the default), while f> functions compose left-to-right (like Threading Macros), which some consider more intuitive. f is an alias for the more verbose make-function, and likewise, f> is an alias for make-threading-function.

Examples:
> (f add1)

'(λ (_) (.. #<procedure:add1>))

> (f add1 ->number)

'(λ (_) (.. #<procedure:add1> #<procedure:->number>))

> ((f ->string add1 ->number) "12")

"13"

> ((f> ->number add1 ->string) "12")

"13"

> (define (str-append x y z) (string-append x y z))
> ((f str-append) "hello")

'(λ ("hello" _) (.. #<procedure:str-append>))

> ((((f str-append) "hello") "there") "friend")

"hellotherefriend"

5.4.2 Function Application

An application scheme represents a definition of function application, entailing how arguments are to be ordered and compiled, what arguments are expected and whether they may be passed in incrementally, and what happens when the function is actually invoked.

The default application scheme is partial application with currying. Other schemes provided include partial application without currying, and template-based partial application (resembling the scheme in Fancy App: Scala-Style Magic Lambdas).

Application schemes compose naturally, so that, for example, a function could expect arguments to match a template, and could receive those arguments incrementally via curried partial application. The examples below illustrate this.

Examples:
> ((partial + 1) 2)

3

> ((curry expt 2) 5)

32

> ((curryr expt 2) 5)

25

> (app string-append _ ", " _ ", " _ " " "and " _ ".")

'(λ (_ ", " _ ", " _ " " "and " _ ".") (.. #<procedure:string-append>))

> ((app string-append _ ", " _ ", " _ " " "and " _ ".") "parsley" "sage")

Not enough arguments, expected: 4

> (curryr (app string-append _ ", " _ ", " _ " " "and " _ ".") "thyme")

'(λ (_ "thyme")

   (.. (λ (_ ", " _ ", " _ " " "and " _ ".") (.. #<procedure:string-append>))))

> (curry (curryr (app string-append _ ", " _ ", " _ " " "and " _ ".") "thyme") "parsley" "sage")

'(λ ("parsley" "sage" _ "thyme")

   (.. (λ (_ ", " _ ", " _ " " "and " _ ".") (.. #<procedure:string-append>))))

> ((curry (curryr (app string-append _ ", " _ ", " _ " " "and " _ ".") "thyme") "parsley" "sage") "rosemary")

"parsley, sage, rosemary and thyme."

procedure

(application-scheme? v)  boolean?

  v : any/c
Predicate to check if a value is an application scheme.

Examples:

To define custom application schemes, the following methods need to be implemented.

procedure

(pass application-scheme args chirality)  application-scheme?

  application-scheme : application-scheme?
  args : arguments?
  chirality : (one-of/c 'left 'right)
Incorporate fresh args into the application-scheme, honoring the "chirality" or order in which the arguments are to be parsed - either left-to-right, or right-to-left, if applicable. This defines what happens when a function with the given application scheme is applied to fresh arguments. The result of this function is expected to be an updated application scheme.

procedure

(flat-arguments application-scheme)  arguments?

  application-scheme : application-scheme?
Produce a flat arguments structure representing the arguments that will be passed in a single invocation of the underlying function. The application scheme may compile the arguments in whatever manner it sees fit; the produced arguments structure represents the result of its operation.

procedure

(handle-failure application-scheme    
  exception)  application-scheme?
  application-scheme : application-scheme?
  exception : exn:fail?
If the function using the application scheme fails when applied, this method is called to give the application scheme an opportunity to define what happens. One of two things must happen: either a fresh application scheme object should be produced (often this is simply the object itself, signaling partial application which may succeed on a future invocation), or an exception (possibly exception itself) should be raised. Note that if any exceptions occur in the process of application that are clear errors reported by the underlying function (e.g. more arguments than it accepts), those would simply be raised directly and would not be forwarded to this method to solicit a contingency plan.

struct

(struct curried-arguments (left right kw))

  left : list?
  right : list?
  kw : hash?

value

empty-curried-arguments : curried-arguments?

An application scheme representing the arguments that parametrize (i.e. have already been supplied to) a function. This includes all arguments that have been supplied by either left- or right-currying.

empty-curried-arguments represents an empty set of curried arguments, often used as the initial application scheme in a curried function that may accumulate arguments over time.

struct

(struct template-arguments (pos kw))

  pos : list?
  kw : hash?
An application scheme encoding a template expressing the expected arguments – whether positional or keyword – to a function. The values of positional or keyword arguments are expected to be optional values. Typically, template-based partial application would be used via the app macro, so that there is no need to muck about with optional values in normal usage.