(The examples here work with the version of insidefunctor tagged as "v2")
Unfortunately I couldn't do this cleanly outside the library. So the changes
are made in insidefunctor
.
Levels are no longer used to "line up" each
es. So, for
example,
> library(insidefunctor)
> `%+.%` = fmap(`+`)
> `%/.%` = fmap(`/`)
> x = c(1, 2, 3)
> y = c(4, 5, 6)
> .[z] = each(x) %+.% each(y)
> z
-
5 6 7
-
6 7 8
-
7 8 9
> .[w] = each(x) %+.% pond(y)
> w
5 7 9
where "pond" stands for "corresponding" and is chosen because no one would use the word pond for anything else.
But this is so much more flexible! Because the definition of "corresponding" is itself flexible. Here it means "having the same sequential position", but it could be taken to mean just about anything else. Like, for example, a linearly-interpolated lookup-table:
> `%near%` = function(y, x) {
> UseMethod("%near%")
> }
> looktable = function(dep, ind) {
> reorder = order(ind)
> dep = dep[reorder]
> ind = ind[reorder]
> attr(dep, "indvar") = ind
> class(dep) = c("looktable", class(dep))
> dep
> }
> `%near%.looktable` = function(y, x) {
> pond(approx(attr(y, "indvar"), y, x)$y)
> }
All it does is translate linear nearness into sequential correspondence, ie exactly what approx() does in the first place. Then you can use it like
> .[u] = each(1:5) %+.% reeval(runif(1))
> u
1.29927378566936 2.63695163559169 3.90192435029894 4.71558610373177 5.38200953858905
> v = looktable((0:6)^2, 0:6)
> v
0 1 4 9 16 25 36
> .[w] = v %near% u
> w
1.89782135700807 7.18475817795843 15.3134704520926 22.4402749335859 29.2021049244795
> .[z] = (v %near% u) %/.% each(u)
> z
1.46067855592911 2.72464541290166 3.92459439940689 4.75874566595812 5.42587387017808
These could of course have been done just as easily in straight-up R. The only difference is grammar. You can generalize corresponding to other kindns of lookups, like, say, functions:
This is a little trickier because if you were to say
> each(u) %/.% the(sin)
when the(sin)
is called it has no idea what axis it runs along, ie
it can't sequentially correspond at that time. Luckily the definition of
correspondence is flexibly: it is done through several generic functions:
> corresponds = function(arg, inside) {
> UseMethod("corresponds")
> }
> alignable = function(arg, inside) {
> UseMethod("alignable")
> }
> corresponding = function(arg, inside, i) {
> UseMethod("corresponding")
> }
With defaults suitable for sequential correspondence:
> corresponds.correspondence = function(arg, inside) {
> if (is.null(arg$ref)) {
> T
> }
> else {
> identical(arg$axis, inside$axis)
> }
> }
> alignable.correspondence = function(arg, inside) {
> identical(arg$axis, inside$axis)
> }
> corresponding.each = function(arg, inside, i) {
> part = arg$items[[i]]
> arg$items[[i]]
> }
So all we need to do is provide methods to tell
apply.functor.each
that the(sin)
corresponds to
each(u)
, that they are alignable, and, given an element of
u
, to find the corresponding element in the(sin)
.
> the = function(func) {
> the = list(
> func = func
> )
> class(the) = c('the', class(the))
> the
> }
> corresponds.the = function(the, inside) {
> T
> }
> alignable.the = function(the, inside) {
> T
> }
> corresponding.the = function(the, inside, i) {
> the$func(inside$items[[i]])
> }
Now see if that works:
> u = c(1, 2, 3)
> u
1 2 3
> .[v] = each(u) %/.% the(sin)
> v
1.18839510577812 2.19950034058923 21.2585021872116
Alas we still could not do
> plot(each(seq(0, 1, len = 100)), the(sin))
because the elements would not be collected at the time of calling plot(). Perhaps another functor could fix this.