Several ggdist functions support *automatic partial application*: when called,
if all of their required arguments have not been provided, the function returns a
modified version of itself that uses the arguments passed to it so far as defaults.
Technically speaking, these functions are essentially "Curried" with respect to
their required arguments, but I think "automatic partial application" gets
the idea across more clearly.

Functions supporting automatic partial application include:

The

`point_interval()`

family, such as`median_qi()`

,`mean_qi()`

,`mode_hdi()`

, etc.The

`smooth_`

family, such as`smooth_bounded()`

,`smooth_unbounded()`

,`smooth_discrete()`

, and`smooth_bar()`

.The

`density_`

family, such as`density_bounded()`

,`density_unbounded()`

and`density_histogram()`

.The align family.

The breaks family.

The bandwidth family.

The blur family.

Partial application makes it easier to supply custom parameters to these
functions when using them inside other functions, such as geoms and stats.
For example, smoothers for `geom_dots()`

can be supplied in one of three
ways:

as a suffix:

`geom_dots(smooth = "bounded")`

as a function:

`geom_dots(smooth = smooth_bounded)`

as a partially-applied function with options:

`geom_dots(smooth = smooth_bounded(kernel = "cosine"))`

Many other common arguments for ggdist functions work similarly; e.g.
`density`

, `align`

, `breaks`

, `bandwidth`

, and `point_interval`

arguments.

Use the `auto_partial()`

function to create new functions that support
automatic partial application.

## Arguments

- f
A function

- name
A character string giving the name of the function, to be used when printing.

## Value

A modified version of `f`

that will automatically be partially
applied if all of its required arguments are not given.

## Examples

```
set.seed(1234)
x = rnorm(100)
# the first required argument, `x`, of the density_ family is the vector
# to calculate a kernel density estimate from. If it is not provided, the
# function is partially applied and returned as-is
density_unbounded()
#> <partial_function>:
#> density_unbounded()
# we could create a new function that uses half the default bandwidth
density_half_bw = density_unbounded(adjust = 0.5)
density_half_bw
#> <partial_function>:
#> density_unbounded(adjust = 0.5)
# we can overwrite partially-applied arguments
density_quarter_bw_trimmed = density_half_bw(adjust = 0.25, trim = TRUE)
density_quarter_bw_trimmed
#> <partial_function>:
#> density_unbounded(adjust = 0.25, trim = TRUE)
# when we eventually call the function and provide the required argument
# `x`, it is applied using the arguments we have "saved up" so far
density_quarter_bw_trimmed(x)
#>
#> Call:
#> density_unbounded(x = x, adjust = 0.25, trim = TRUE)
#>
#> Data: x (100 obs.); Bandwidth 'bw' = 0.08864
#>
#> x y
#> Min. :-2.3457 Min. :0.009921
#> 1st Qu.:-1.1220 1st Qu.:0.062906
#> Median : 0.1016 Median :0.149478
#> Mean : 0.1016 Mean :0.201970
#> 3rd Qu.: 1.3253 3rd Qu.:0.337508
#> Max. : 2.5490 Max. :0.673160
# create a custom automatically partially applied function
f = auto_partial(function(x, y, z = 3) (x + y) * z)
f()
#> <partial_function>:
#> f()
f(1)
#> <partial_function>:
#> f(x = 1)
g = f(y = 2)(z = 4)
g
#> <partial_function>:
#> f(y = 2, z = 4)
g(1)
#> [1] 12
```