r/rstats • u/Spirited-Sir8426 • 13h ago
I didn't build TypR for AI — but it turns out a type-checked layer over R is a surprisingly good fit for reviewing AI-generated code. Some thoughts, and I'd like your pushback.
Some of you have followed my earlier posts on TypR here. This one's less "what's new" and more the reasoning behind the design — I'd like your pushback on the thinking itself.
The honest origin story: I didn't build TypR for AI. I built it because I care about type systems (academic background) and about code that survives production (industry background) — verifiability, basically.
What clicked more recently is that the property making code cheap for a human to verify is the same one that matters when a machine wrote it.
As AI writes more of the code, the expensive part stops being writing it and becomes trusting it — reviewing, validating, maintaining. A strict type system becomes a free automatic checker on whatever got generated; concise syntax means less to misread.
So the fit with the AI era isn't something I designed for — it's the same property suddenly mattering a lot more. That's the accidental discovery I wanted to share here.
A small taste — this R:
```
' Create a button widget
'
' @param color \code{char}
' @param height \code{int}
' @param text \code{char}
' @param width \code{int}
' @return \code{Button}
' @export
Button <- function(color, height, text, width, .spread = NULL) { explicit <- list() if (!missing(color)) explicit[["color"]] <- color if (!missing(height)) explicit[["height"]] <- height if (!missing(text)) explicit[["text"]] <- text if (!missing(width)) explicit[["width"]] <- width x <- typr_spread_record(explicit, .spread) as.Button(x) }
as.Button <- function(x) { if (!inherits(x, "Button")) class(x) <- c("Button", "list") x <- validate_Button(x) x <- validate(x) x }
validate_Button <- function(x) { required_fields <- c("color", "height", "text", "width") missing_fields <- setdiff(required_fields, names(x))
if (length(missing_fields) > 0) { stop(paste0("Validation failed for type Button: missing fields: ", paste(missing_fields, collapse = ", "))) }
if (!inherits(x[["color"]], "character")) stop("Validation failed for type Button: field 'color' must be of class character")
if (!inherits(x[["height"]], "integer")) stop("Validation failed for type Button: field 'height' must be of class integer")
if (!inherits(x[["text"]], "character")) stop("Validation failed for type Button: field 'text' must be of class character")
if (!inherits(x[["width"]], "integer")) stop("Validation failed for type Button: field 'width' must be of class integer")
x }
constructor for a red button
' @export
' @method red_button
red_button <- (function(height, width, text) Button(height = height, width = width, text = text, color = "#FF000000" |> as.Character())) |> as.Generic()
add an "on click" callback function
' @export
' @method on_click Button
on_click.Button <- (function(self, f) {
NA
} |> as.Empty0()) |> as.Generic()
```
becomes this TypR: ```
Create a button widget
@export type Button <- list { text: char, color: char, width: int, height: int };
constructor for a red button
@export let red_button <- \Button:{ color: "#FF000000" };
add an "on click" callback function
@export
let on_click <- fn(self: Button, f: (T) -> U): Empty { ... }; ```
The way TypeScript sits on top of JavaScript's runtime, TypR sits on top of R's: you write something concise and type-checked, and it compiles down to standard, S3-based R that runs anywhere R runs and installs like any other package — no new runtime, no exotic dependencies.
To be clear, it's not trying to replace R. R is excellent for interactive stats and lab work, and TypR deliberately gives some of that up in exchange for the other end of the curve: robust packages, deployable apps, code that has to survive production. Different point on the trade-off, different job.
On the engineering side you get pattern matching, partial currying, union/intersection types, structural subtyping, row polymorphism — the machinery that keeps a growing codebase honest. Written in Rust, developed in the open.
Honest questions for this sub: does a typed layer over R solve a problem you actually hit, or is this a solution looking for one? And does the "verifiability matters more when AI writes the code" argument hold up, or am I reaching?
Discussion: https://github.com/we-data-ch/typr/discussions