Skip to content

Commit

Permalink
minor readability pass
Browse files Browse the repository at this point in the history
  • Loading branch information
D-Se committed Nov 28, 2023
1 parent e569b3a commit 4d3c5f1
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 55 deletions.
3 changes: 2 additions & 1 deletion R/ask.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ utils::globalVariables("nil")
do.call(utils::`?`, list(substitute(x))),
{
e <- substitute(x)
if (is.call(e)) { # handle ? low precedence, loss of ~40% performance
if (is.call(e)) { # handle ? low precedence, loss of ~40% performance
switch(
as.character(e[[1]]),
"=" =, # handle nesting x <- y <- TRUE ? 10 ~ 5
Expand All @@ -30,6 +30,7 @@ utils::globalVariables("nil")
)
}

# bare-bones, no precedence elevation
# `?` <- function(x, y) {
# switch(
# nargs(),
Expand Down
77 changes: 38 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# `ask`
Syntax for convenient control flow and type checks/coercion for fast thought-to-code. Fewer syntax errors, less debugging, faster data science.

# `ask` ? yes ~ no
Nice control flow and type checks/coercion syntax for fast thought-to-code. Fewer syntax errors, less debugging, faster data science. Favors terse syntax over common actions over S4 method documentation.
<!-- badges: start -->
[![](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental)
[![](https://codecov.io/gh/D-Se/ask/branch/main/graph/badge.svg)](https://app.codecov.io/gh/D-Se/ask?branch=main)
Expand All @@ -16,42 +15,42 @@ remotes::install_github("D-Se/ask")

## Usage

### Scalar-if
```
e = logical(0)
```
| ask | base | tidy | fast |
|-------------------- |------------------------- |------------------------------ |------------------------------ |
| `T ? 1` | `if(T) 1` | - | - |
| `T ? 1 ~ 2` | `if(T) 1 else 2` | `if_else(T, 1, 2)` | `fifelse(T, 1, 2)` |
| `NA ? 1 ~ 2` [err] | `if(NA) 1 else 2`[err] | `if_else(NA, 1, 2)` [num NA] | `fifelse(NA, 1, 2)` [num NA] |
| `e ? 1 ~ 2` [err] | `if(e) 1 else 2` [err] | `if_else(e, 1, 2)` [num e] | `fifelse(e, 1, 2)` [num e] |

### Vector-if
```
t <- c(T, F, NA)
x <- 1:3
y <- c(7, 8, 9)
```r
# ternary vectorized query operator with elevated precedence
z <- TRUE ? 1 ~ 2

x <- c(TRUE, FALSE, NA)
a <- 1:3; b <- 4:6; c <- 7:9
x ? a ~ {!x ? b ~ c}
x ? a ~ (!x ? b ~ c)

# check types using 3-letter abbreviations
5 ? num
5 ?! num

# coerce types
5 ?~ chr
5 ?~ ""

# scalar-if
TRUE ? 1 ~ 2
TRUE ? 1
FALSE ? 2
FALSE ?~ 2

# happy path guard clauses
TRUE ?~! "message"
FALSE ?~! "message"

# search documentation like usual, except S4 methods
?integer
??regression
```
| ask | base | tidy | fast |
|------------------- |------------------- |-------------------- |-------------------- |
| `t ? 1 ~ 2` | `ifelse(t, 1, 2)` | `if_else(t, 1, 2)` | `fifelse(t, 1, 2)` |
| `t ? x ~ y` [err] | `ifelse(t, x, y)` | `if_else(t, x, y)` | `fifelse(t, x, y)` |

`ask` does not do silent promotion.
## Gotchas

### Type queries

| ask | base | tidy |
|----------- |------------------- |------------------- |
| `x ? chr` | `is.character(x)` | `is_character(x)` |
| `x ? ""` | - | - |

### Type coercion

| ask | base | tidy |
|------------ |------------------- |------------------- |
| `x ?~ chr` | `as.character(x)` | `as_character(x)` |
| `x ?~ ""` | - | - |

`ask` supports abbreviated types and comparison
```r
# all queries must be of the same type
x ? a ~ c(5, 6, 7) # integer is not the same as numeric
x ? a ~ !x ? b ~ c # missing braces, precedence issue
```
6 changes: 3 additions & 3 deletions inst/tinytest/test_isas.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ units <- eval(units)

#### type checking ####
base_is <- vapply(paste0("is.", names), \(fun) {
vapply(units, \(x) do.call(fun, list(x = x)), TRUE)
vapply(units, function(x) do.call(fun, list(x = x)), TRUE)
}, logical(length(units)))

ask_is <- vapply(abbs, \(y) {
vapply(units, \(x) {
ask_is <- vapply(abbs, function(y) {
vapply(units, function(x) {
eval(substitute(x ? y, list(x = x, y = as.name(y))))
}, TRUE)
}, logical(length(units)))
Expand Down
27 changes: 15 additions & 12 deletions man/help.Rd
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
\name{?}
\alias{?}
\title{?: conditions, types and documentation shortcuts}
\title{?: control flow, types and documentation shortcuts}
\description{
Ask objects about types, control flow and documentation.
}
Expand All @@ -24,14 +24,16 @@ are not interchangable with logicals, and strict type checking is applied.
\item \strong{Guard clauses}, \code{x ?~! no} \cr
A simplified \link[base]{stopifnot} where an error occurs if the happy path fails.
\item \strong{Type check}, \code{x ? type} \cr
For non-logical \code{x}, short \link[methods]{is} asks if LHS is of type RHS.
For non-logical \code{x}, short \link[methods]{is}; ask if LHS is of type RHS.
\item \strong{Type coercion}, \code{x ?~ type, x ?~ abb} \cr
For non-logical \code{x}, short \link[methods]{as} coerces LHS to type RHS.
For non-logical \code{x}, short \link[methods]{as}; coerce LHS to type RHS.
}
}
\section{Abbreviations}{

Class checks and coercions support abbreviated type names.\tabular{llll}{
Abbreviated type names. Note: more complex types are yet to be implemented.

\tabular{llll}{
\strong{Atomic} \tab \strong{Bunch} \tab \strong{Language} \tab \strong{Other} \cr
atm \tab rec \tab lang \tab na \cr
lgl \tab lst \tab sym \tab nan \cr
Expand All @@ -53,17 +55,18 @@ Class checks and coercions support abbreviated type names.\tabular{llll}{
5 ?~ ""

# scalar-if
TRUE ? 1 ~ 2
TRUE ? 1
FALSE ? 2
FALSE ?~ 2
y <- TRUE; n <- FALSE
y ? 1 ~ 2
y ? 1
n ? 2
n ?~ 2

# ternary / vector-if, recycled and by position, and elevated precedence
res <- c(TRUE, FALSE) ? 1 ~ 2; res
c(TRUE, FALSE) ? c(3, 4) ~ c(5, 6)
res <- c(y, n) ? 1 ~ 2; res
c(y, n) ? c(3, 4) ~ c(5, 6)

# nested, top-down evaluation
x <- c(TRUE, FALSE, NA)
x <- c(y, n, NA)
a <- 1:3; b <- 4:6; c <- 7:9
x ? a ~ {!x ? b ~ c}
x ? a ~ (!x ? b ~ c)
Expand All @@ -72,7 +75,7 @@ x ? a ~ (!x ? b ~ c)
try(x ? 1:3 ~ c(5, 6, 7)) # integer is not the same as numeric
try(x ? 1:3 ~ !x ? 4:6 ~ 7:9) # missing braces

# search documentation gotchas
# search documentation as usual, except S4 methods
?integer

# guard clauses
Expand Down

0 comments on commit 4d3c5f1

Please sign in to comment.