[Rd] "if" function in pure R?
Hi all, Could anyone refer to me to a good source to learn how to program a simple control-flow construct* in R, or provide me with a simple example? Control-flow constructs are programmed as primitives, but I would like to be able to do that (if possible) in pure R. The general context is that those functions are a mystery to me. The motivating example is that I would like to create a function that behave similarly to base::`if` with an extra argument to the function (e.g. to include an error rate on the condition). Many thanks, Alex * control-flow constructs are functions such as if, for, while... that allow for call of the form fn(x) expr to work (see ?Control). -- Alexandre Courtiol http://sites.google.com/site/alexandrecourtiol/home *"Science is the belief in the ignorance of experts"*, R. Feynman [[alternative HTML version deleted]] __ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
Re: [Rd] rbind has confusing result for custom sub-class (possible bug?)
Have finally managed to come up with a fix after checking out sys.calls() from within the as.Date.IDate debugger, which shows something like: [[1]] rbind(DF, DF) [[2]] rbind(deparse.level, ...) [[3]] `[<-`(`*tmp*`, ri, value = 18042L) [[4]] `[<-.Date`(`*tmp*`, ri, value = 18042L) [[5]] as.Date(value) [[6]] as.Date.IDate(value) I'm not sure why [<- is called, I guess the implementation is to assign to the output block by block? Anyway, we didn't have a [<- method. And [<-.Date looks like: value <- unclass(as.Date(value)) # <- converts to double .Date(NextMethod(.Generic), oldClass(x)) # <- restores 'IDate' class So we can fix our bug by defining a [<- class; the question that I still don't see answered in documentation or source code is, why/where is [<- called, exactly? Mike C On Sun, May 26, 2019 at 1:16 PM Michael Chirico wrote: > Debugging this issue: > > https://github.com/Rdatatable/data.table/issues/2008 > > We have custom class 'IDate' which inherits from 'Date' (it just forces > integer storage for efficiency, hence, I). > > The concatenation done by rbind, however, breaks this and returns a double: > > library(data.table) > DF = data.frame(date = as.IDate(Sys.Date())) > storage.mode(rbind(DF, DF)$date) > # [1] "double" > > This is specific to base::rbind (data.table's rbind returns an integer as > expected); in ?rbind we see: > > The method dispatching is not done via UseMethod(), but by C-internal > dispatching. Therefore there is no need for, e.g., rbind.default. > The dispatch algorithm is described in the source file > (ā.../src/main/bind.cā) as > 1. For each argument we get the list of possible class memberships from > the class attribute. > 2. *We inspect each class in turn to see if there is an applicable > method.* > 3. If we find an applicable method we make sure that it is identical to > any method determined for prior arguments. If it is identical, we proceed, > otherwise we immediately drop through to the default code. > > It's not clear what #2 means -- an applicable method *for what*? Glancing > at the source code would suggest it's looking for rbind.IDate: > > https://github.com/wch/r-source/blob/trunk/src/main/bind.c#L1051-L1063 > > const char *generic = ((PRIMVAL(op) == 1) ? "cbind" : "rbind"); // should > be rbind here > const char *s = translateChar(STRING_ELT(classlist, i)); // iterating over > the classes, should get to IDate first > sprintf(buf, "%s.%s", generic, s); // should be rbind.IDate > > but adding this method (or even exporting it) is no help [ simply defining > rbind.IDate = function(...) as.IDate(NextMethod()) ] > > Lastly, it appears that as.Date.IDate is called, which is causing the type > conversion: > > debug(data.table:::as.Date.IDate) > rbind(DF, DF) # launches debugger > x > # [1] "2019-05-26" <-- singleton, so apparently applied to DF$date, not > c(DF$date, DF$date) > undebug(data.table:::as.Date.IDate) > > I can't really wrap my head around why as.Date is being called here, and > even allowing that, why the end result is still the original class [ > class(rbind(DF, DF)$date) == c('IDate', 'Date') ] > > So, I'm beginning to think this might be a bug. Am I missing something? > [[alternative HTML version deleted]] __ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
Re: [Rd] rbind has confusing result for custom sub-class (possible bug?)
On Sun, May 26, 2019 at 4:06 AM Michael Chirico wrote: > > Have finally managed to come up with a fix after checking out sys.calls() > from within the as.Date.IDate debugger, which shows something like: > > [[1]] rbind(DF, DF) > [[2]] rbind(deparse.level, ...) > [[3]] `[<-`(`*tmp*`, ri, value = 18042L) > [[4]] `[<-.Date`(`*tmp*`, ri, value = 18042L) > [[5]] as.Date(value) > [[6]] as.Date.IDate(value) > > I'm not sure why [<- is called, I guess the implementation is to assign to > the output block by block? Anyway, we didn't have a [<- method. And > [<-.Date looks like: > > value <- unclass(as.Date(value)) # <- converts to double > .Date(NextMethod(.Generic), oldClass(x)) # <- restores 'IDate' class > > So we can fix our bug by defining a [<- class; the question that I still > don't see answered in documentation or source code is, why/where is [<- > called, exactly? > Your rbind(DF, DF) call dispatches to base::rbind.data.frame(). The `[<-` call is this line: value[[jj]][ri] <- if (is.factor(xij)) as.vector(xij) else xij That's where the storage.mode changes from integer to double. debug: value[[jj]][ri] <- if (is.factor(xij)) as.vector(xij) else xij Browse[2]> debug: xij Browse[2]> storage.mode(xij) [1] "integer" Browse[2]> value[[jj]][ri] [1] "2019-05-26" Browse[2]> storage.mode(value[[jj]][ri]) [1] "integer" Browse[2]> debug: if (!is.null(nm <- names(xij))) names(value[[jj]])[ri] <- nm Browse[2]> storage.mode(value[[jj]][ri]) [1] "double" > Mike C > > On Sun, May 26, 2019 at 1:16 PM Michael Chirico > wrote: > > > Debugging this issue: > > > > https://github.com/Rdatatable/data.table/issues/2008 > > > > We have custom class 'IDate' which inherits from 'Date' (it just forces > > integer storage for efficiency, hence, I). > > > > The concatenation done by rbind, however, breaks this and returns a double: > > > > library(data.table) > > DF = data.frame(date = as.IDate(Sys.Date())) > > storage.mode(rbind(DF, DF)$date) > > # [1] "double" > > > > This is specific to base::rbind (data.table's rbind returns an integer as > > expected); in ?rbind we see: > > > > The method dispatching is not done via UseMethod(), but by C-internal > > dispatching. Therefore there is no need for, e.g., rbind.default. > > The dispatch algorithm is described in the source file > > (ā.../src/main/bind.cā) as > > 1. For each argument we get the list of possible class memberships from > > the class attribute. > > 2. *We inspect each class in turn to see if there is an applicable > > method.* > > 3. If we find an applicable method we make sure that it is identical to > > any method determined for prior arguments. If it is identical, we proceed, > > otherwise we immediately drop through to the default code. > > > > It's not clear what #2 means -- an applicable method *for what*? Glancing > > at the source code would suggest it's looking for rbind.IDate: > > > > https://github.com/wch/r-source/blob/trunk/src/main/bind.c#L1051-L1063 > > > > const char *generic = ((PRIMVAL(op) == 1) ? "cbind" : "rbind"); // should > > be rbind here > > const char *s = translateChar(STRING_ELT(classlist, i)); // iterating over > > the classes, should get to IDate first > > sprintf(buf, "%s.%s", generic, s); // should be rbind.IDate > > > > but adding this method (or even exporting it) is no help [ simply defining > > rbind.IDate = function(...) as.IDate(NextMethod()) ] > > > > Lastly, it appears that as.Date.IDate is called, which is causing the type > > conversion: > > > > debug(data.table:::as.Date.IDate) > > rbind(DF, DF) # launches debugger > > x > > # [1] "2019-05-26" <-- singleton, so apparently applied to DF$date, not > > c(DF$date, DF$date) > > undebug(data.table:::as.Date.IDate) > > > > I can't really wrap my head around why as.Date is being called here, and > > even allowing that, why the end result is still the original class [ > > class(rbind(DF, DF)$date) == c('IDate', 'Date') ] > > > > So, I'm beginning to think this might be a bug. Am I missing something? > > > > [[alternative HTML version deleted]] > > __ > R-devel@r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel -- Joshua Ulrich | about.me/joshuaulrich FOSS Trading | www.fosstrading.com R/Finance 2019 | www.rinfinance.com __ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
Re: [Rd] "if" function in pure R?
Hi Alexandre, I'm not an R expert so this is only my personal thought: I don't think you can achieve what you want exactly. A possible solution would be defining a binary operator %*%, where you can replace the asterisk with any function name you want. The function %*% is special since it has two arguments, left operand and right operand respectively. You then can call the `substitute` function to get its function arguments in an expression format and proceed to do what you want. Here is an example to show the idea. *Code:* `%myOperator%` <- function(x, y) { x = substitute(x) y = substitute(y) return(list(x, y)) } myIf(i == 1, arg1) %myOperator% { doSomeThing } *Results:* [[1]] myIf(i == 1, arg1) [[2]] { doSomeThing } I hope that helps. Best, Jiefei On Sun, May 26, 2019 at 4:45 AM Alexandre Courtiol < alexandre.court...@gmail.com> wrote: > Hi all, > > Could anyone refer to me to a good source to learn how to program a simple > control-flow construct* in R, or provide me with a simple example? > > Control-flow constructs are programmed as primitives, but I would like to > be able to do that (if possible) in pure R. > > The general context is that those functions are a mystery to me. The > motivating example is that I would like to create a function that behave > similarly to base::`if` with an extra argument to the function (e.g. to > include an error rate on the condition). > > Many thanks, > > Alex > > * control-flow constructs are functions such as if, for, while... that > allow for call of the form fn(x) expr to work (see ?Control). > > -- > Alexandre Courtiol > > http://sites.google.com/site/alexandrecourtiol/home > > *"Science is the belief in the ignorance of experts"*, R. Feynman > > [[alternative HTML version deleted]] > > __ > R-devel@r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel > [[alternative HTML version deleted]] __ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
Re: [Rd] "if" function in pure R?
Thanks a lot Jiefei, I had thought of defining a binary operator (inspired by pipes) or simply using an additional condition in the if() calls [e.g. if(foo & fn(bar)) doSomeThing; with fn(bar) returning a logical], but both are workaround that I do not find as elegant as a proper control-flow construct. Thus two questions remain: - is it possible to create a control-flow construct in pure R? - if yes, how? Anyone with more insights? Thanks On Mon, 27 May 2019 at 04:27, King Jiefei wrote: > Hi Alexandre, > > I'm not an R expert so this is only my personal thought: > > I don't think you can achieve what you want exactly. A possible solution > would be defining a binary operator %*%, where you can replace the asterisk > with any function name you want. The function %*% is special since it has > two arguments, left operand and right operand respectively. You then > can call the `substitute` function to get its function arguments in an > expression format and proceed to do what you want. Here is an example to > show the idea. > > *Code:* > > `%myOperator%` <- function(x, y) { > x = substitute(x) > y = substitute(y) > return(list(x, y)) > } > > > myIf(i == 1, arg1) %myOperator% { > doSomeThing > } > > > *Results:* > > [[1]] > myIf(i == 1, arg1) > > [[2]] > { > doSomeThing > } > > I hope that helps. > > Best, > Jiefei > > On Sun, May 26, 2019 at 4:45 AM Alexandre Courtiol < > alexandre.court...@gmail.com> wrote: > >> Hi all, >> >> Could anyone refer to me to a good source to learn how to program a simple >> control-flow construct* in R, or provide me with a simple example? >> >> Control-flow constructs are programmed as primitives, but I would like to >> be able to do that (if possible) in pure R. >> >> The general context is that those functions are a mystery to me. The >> motivating example is that I would like to create a function that behave >> similarly to base::`if` with an extra argument to the function (e.g. to >> include an error rate on the condition). >> >> Many thanks, >> >> Alex >> >> * control-flow constructs are functions such as if, for, while... that >> allow for call of the form fn(x) expr to work (see ?Control). >> >> -- >> Alexandre Courtiol >> >> http://sites.google.com/site/alexandrecourtiol/home >> >> *"Science is the belief in the ignorance of experts"*, R. Feynman >> >> [[alternative HTML version deleted]] >> >> __ >> R-devel@r-project.org mailing list >> https://stat.ethz.ch/mailman/listinfo/r-devel >> > -- Alexandre Courtiol http://sites.google.com/site/alexandrecourtiol/home *"Science is the belief in the ignorance of experts"*, R. Feynman [[alternative HTML version deleted]] __ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel