[Rd] "interpolator constructor"; was "Scope problem?"

Martin Maechler
Mon, 25 May 2009 15:08:11 -0000

Hi Barry,

this is just a side-remark, probably not at all something you
were interested in, but to be put along this thread in the list
archives, in case some readers are side-tracked there ...

>>>>> "BaRow" == Barry Rowlingson <b.rowlingson at
lancaster.ac.uk>
>>>>>     on Fri, 22 May 2009 17:28:42 +0100 writes:

    BaRow> I've just spent today trying to fix a Heisenbug...
    BaRow> this function returns a linear interpolator function:

    BaRow> interpOne <- function(xl,yl){
    BaRow> f = function(data){
    BaRow> t = (data-min(xl))/(max(xl)-min(xl))
    BaRow> return(min(yl)+t*(max(yl)-min(yl)))
    BaRow> }
    BaRow> return(f)
    BaRow> }

    >> k=interpOne(c(0,1),c(4,5))
    >> k(0.5)
    BaRow> [1] 4.5

Note that "base R" has already two such functions,
namely
	  splinefun()
and       approxfun(),
both returning a *function* as in your examples.

Best,
Martin Maechler, ETH Zurich

    BaRow> and this function uses the above to return a function that returns
a
    BaRow> piece-wise linear interpolator function:

    BaRow> mr <- function(){
    BaRow> parts = list()
    BaRow> ranges =  rbind(c(0,1),c(1,2),c(2,3))
    BaRow> domains = rbind(c(3,4),c(5,6),c(2,8))
    BaRow> for(i in 1:length(ranges[,1])){
    BaRow> parts[[i]] = interpOne(ranges[i,],domains[i,])
    BaRow> }

    BaRow> f = function(d){
    BaRow> pos = sum(d>ranges[,1])
    BaRow> cat("using pos = ",pos,"\n")
    BaRow> return(parts[[pos]](d))
    BaRow> }
    BaRow> return(f)
    BaRow> }

    BaRow> m = mr()

    BaRow> The 'ranges' and 'domains' vectors describe the
pieces. But this doesn't work:
    >> m(0.5)
    BaRow> using pos =  1
    BaRow> [1] -7

    BaRow> - but it should be 3.5 (since 0.5 is in the first piece, and that
    BaRow> then interpolates between 3 and 4). What about the other pieces:

    >> m(1.5)
    BaRow> using pos =  2
    BaRow> [1] -1
    >> m(2.5)
    BaRow> using pos =  3
    BaRow> [1] 5

    BaRow> - which looks like it's using the last set of range/domain
pairs each
    BaRow> time. Curious, I thought.

    BaRow> So I thought I'd evaluate the functions as they are created in
the
    BaRow> list to see what's going on. Change the loop to print out:

    BaRow> for(i in 1:length(ranges[,1])){
    BaRow> parts[[i]] = interpOne(ranges[i,],domains[i,])
    BaRow> cat("part ",i," at zero =
",parts[[i]](0),"\n")
    BaRow> }

    BaRow> and try:

    >> m=mr()
    BaRow> part  1  at zero =  3
    BaRow> part  2  at zero =  4
    BaRow> part  3  at zero =  -10

    BaRow> looks good, those are the intercepts of my pieces... but now:

    >> m(0.5)
    BaRow> using pos =  1
    BaRow> [1] 3.5
    >> m(1.5)
    BaRow> using pos =  2
    BaRow> [1] 5.5
    >> m(2.5)
    BaRow> using pos =  3
    BaRow> [1] 5

    BaRow> Woah! It's now working!  Trying to observe the thing changes
it? A Heisenbug!

    BaRow> I can only think it's my misunderstanding of some aspect of
R's
    BaRow> scoping and evaluation rules. Does evaluating the functions within
    BaRow> that loop cause a copy of some environment to be made, or a
'lazy
    BaRow> evaluation' to be evaluated? Or a 'promise' to be
fulfilled? I don't
    BaRow> really understand those terms, I'd just hoped functions ran in
the
    BaRow> environment they were created in. Seems sometimes they do,
sometimes
    BaRow> they dont... What's going on?

    BaRow> R 2.9.0 on Ubuntu.

    BaRow> Barry

    BaRow> ______________________________________________
    BaRow> R-devel at r-project.org mailing list
    BaRow> https://stat.ethz.ch/mailman/listinfo/r-devel