---
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.
