--- title: "Inner Functions and Custom Types" author: "Konrad Kraemer" output: html_document vignette: > %\VignetteIndexEntry{Inner Functions and Custom Types} %\VignetteEngine{knitr::rmarkdown} \usepackage{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE, eval = FALSE) ``` This vignette gives a brief, combined example of two **ast2ast** features: functions defined *inside* the translated function (`fn`), and user-defined struct types (`new_type`). See the "Detailed Documentation" vignette for the full reference. ## Defining a custom type A custom type is declared in a `types_f` helper and passed to `translate()` via `types_f =`. Each slot gets a type via `type()`: ```{r} types_f <- function() { new_type(Point, slots(x |> type(double), y |> type(double))) } ``` On the R side, a value of this type is a named list with a matching `class` attribute: `structure(list(x = 1, y = 2), class = "Point")`. ## An inner function operating on the type `fn()` defines a function local to `f`. It takes three positional parts: `argtypes(...)` (argument types), `return(...)` (return type), and a `{ }` block (the function body). The outer function declares its own argument types with `argtypes(...)` as the first statement of its body: ```{r} f <- function(p, q) { argtypes( p |> type(Point), q |> type(Point) ) squared_dist <- fn( argtypes( a |> type(Point) |> const() |> ref(), b |> type(Point) |> const() |> ref() ), return(double), { dx <- a$x - b$x dy <- a$y - b$y return(dx * dx + dy * dy) } ) return(squared_dist(p, q)) } ``` ## Translating and calling it ```{r} fcpp <- ast2ast::translate(f, types_f = types_f) p <- structure(list(x = 0, y = 0), class = "Point") q <- structure(list(x = 3, y = 4), class = "Point") fcpp(p, q) # 25 ``` Inner functions may call each other (including recursively) and can be passed as values to functions expecting a function argument: `uniroot()`, the functionals `map()`, `Reduce()`, `Filter()`, `apply()`, and the optimizers `jacobian()`, `lbfgsb()`, `pso()`. Struct fields are read and written with `$`, and a slot can itself be a custom type or a `collection(TypeName)` (a vector of a custom type), enabling nested structs and vectors of structs.