(I'm using the word "field" in the mathematical sense; base fields/corpora which R
already uses include the real and complex numbers.)
I'm interested in allowing some other base fields/corpora (like F₅, which is modular arithmetic in base 5). To do that I would need to
- define a new data type
- overload the relevant operators (
+
, *
, and maybe more)
- maybe something else? e.g., integrate with other functionality?
So, how does one define a new data type or overload operators in R
?
I found Hadley Wickham's devtools wiki an invaluable resource for getting started with classes in R. In particular, read the sections on:
Here is a starting point that illustrates some of the concepts in S3
classes. Let's call your new class f5
. At a minimum, you would probably want to create methods for:
- Coercion:
as.f5
- Test:
is.f5
- Some basic operators:
+.f5
- A class to handle printing:
print.f5
Some code (using digitsBase
in package GLDEX
to do the base conversion):
library(GLDEX)
as.f5 <- function(x){
if(!inherits(x, "f5")) class(x) <- c("f5", class(x))
x
}
is.f5 <- function(x){
inherits(x, "f5")
}
`+.f5` <- function(e1, e2){
NextMethod(e1, e2)
}
print.f5 <- function(x, ...){
# Next line from ?GLDEX::digitsBase
b2ch <- function(db) noquote(gsub("^0+(.{1,})$"," \1",
apply(db, 2, paste, collapse = "")))
cat("Base 5:\n")
cat(b2ch(digitsBase(x, 5)))
invisible(x)
}
x <- as.f5(0:10)
y <- as.f5(5)
x + y
Base 5:
10 11 12 13 14 20 21 22 23 24 30
I interpreted your question a bit differently than @Andrie, but he has already done a bunch of the needed S3 class work. I thought you wanted to develop group operations on a group with five elements, or perhaps a ring. You would then want a "+" operation with an identity element == 0 and perhaps a "*" operation with an identity element == 1.
If you wanted the nonnegative integers mapped into this, you would use the modulo arithmetic operators, %%
and perhaps %/%
:
?Ops
as.g5 <- function(x){
if(!inherits(x, "g5")) class(x) <- c("g5", class(x))
x %% 5
}
print.g5 <- function(x, ...){
cat("G5 equivalent:\n")
cat(x %% 5)
invisible(x)
}
If you wanted two operators you might be looking for:
`+.g5` <- function(e1, e2){
NextMethod(e1 ,e2) %% 5
}
`*.g5` <- function(e1, e2){
NextMethod(e1 ,e2) %% 5
}
x <- as.g5(0:10)
y <- as.g5(5)
x + y
#G5 equivalent:
#0 1 2 3 4 0 1 2 3 4 0
y <- as.g5(2)
x * y
#G5 equivalent:
#0 2 4 1 3 0 2 4 1 3 0
It's also possible to use these operation on "volatile" versions of vectors:
as.g5(1:10) * as.g5(1:10)
# G5 equivalent:
# 1 4 4 1 0 1 4 4 1 0