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():

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:

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

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.