#lang scribble/doc
@(require scribble/manual
          scribble/eval
          "guide-utils.ss")

@title[#:tag "application"]{Function Calls@aux-elem{ (Procedure Applications)}}

An expression of the form

@specsubform[
(proc-expr arg-expr ...)
]

is a function call---also known as a @defterm{procedure
application}---when @racket[_proc-expr] is not an identifier that is
bound as a syntax transformer (such as @racket[if] or
@racket[define]).

@section{Evaluation Order and Arity}

A function call is evaluated by first evaluating the
@racket[_proc-expr] and all @racket[_arg-expr]s in order (left to
right). Then, if @racket[_proc-expr] produces a function that accepts
as many arguments as supplied @racket[_arg-expr]s, the function is
called. Otherwise, an exception is raised.

@examples[
(cons 1 null)
(+ 1 2 3)
(cons 1 2 3)
(1 2 3)
]

Some functions, such as @racket[cons], accept a fixed number of
arguments. Some functions, such as @racket[+] or @racket[list], accept
any number of arguments. Some functions accept a range of argument
counts; for example @racket[substring] accepts either two or three
arguments. A function's @idefterm{arity} is the number of arguments
that it accepts.

@;------------------------------------------------------------------------
@section[#:tag "keyword-args"]{Keyword Arguments}

Some functions accept @defterm{keyword arguments} in addition to
by-position arguments. For that case, an @racket[_arg] can be an
@racket[_arg-keyword _arg-expr] sequence instead of just a
@racket[_arg-expr]:

@guideother{@secref["keywords"] introduces keywords.}

@specform/subs[
(_proc-expr arg ...)
([arg arg-expr
      (code:line arg-keyword arg-expr)])
]

For example,

@racketblock[(go "super.ss" #:mode 'fast)]

calls the function bound to @racket[go] with @racket["super.ss"] as a
by-position argument, and with @racket['fast] as an argument
associated with the @racket[#:mode] keyword. A keyword is implicitly
paired with the expression that follows it.

Since a keyword by itself is not an expression, then

@racketblock[(go "super.ss" #:mode #:fast)]

is a syntax error. The @racket[#:mode] keyword must be followed by an
expression to produce an argument value, and @racket[#:fast] is not an
expression.

The order of keyword @racket[_arg]s determines the order in which
@racket[_arg-expr]s are evaluated, but a function accepts keyword
arguments independent of their position in the argument list. The
above call to @racket[go] can be equivalently written

@racketblock[(go #:mode 'fast "super.ss")]

@refdetails["application"]{procedure applications}

@;------------------------------------------------------------------------
@section[#:tag "apply"]{The @racket[apply] Function}

The syntax for function calls supports any number of arguments, but a
specific call always specifies a fixed number of arguments. As a
result, a function that takes a list of arguments cannot directly
apply a function like @racket[+] to all of the items in the list:

@def+int[
(define (avg lst) (code:comment @#,elem{doesn't work...})
  (/ (+ lst) (length lst)))
(avg '(1 2 3))
]

@def+int[
(define (avg lst) (code:comment @#,elem{doesn't always work...})
 (/ (+ (list-ref lst 0) (list-ref lst 1) (list-ref lst 2))
    (length lst)))
(avg '(1 2 3))
(avg '(1 2))
]

The @racket[apply] function offers a way around this restriction. It
takes a function and a @italic{list} arguments, and it applies the
function to the arguments:

@def+int[
(define (avg lst)
  (/ (apply + lst) (length lst)))
(avg '(1 2 3))
(avg '(1 2))
(avg '(1 2 3 4))
]

As a convenience, the @racket[apply] function accepts additional
arguments between the function and the list. The additional arguments
are effectively @racket[cons]ed onto the argument list:

@def+int[
(define (anti-sum lst)
  (apply - 0 lst))
(anti-sum '(1 2 3))
]

The @racket[apply] function supports only by-position arguments. To
apply a function with keyword arguments, use the
@racket[keyword-apply] function, which accepts a function to apply
and three lists. The first two lists are in parallel, where the first
list contains keywords (sorted by @racket[keyword<]), and the second
list contains a corresponding argument for each keyword. The third
list contains by-position function arguments, as for @racket[apply].

@racketblock[
(keyword-apply go
               '(#:mode)
               '(fast)
               '("super.ss"))
]
