Hi, hopefully someone out there is good with foreach and iterators! I've been struggling with this:
I have created a custom iterator, inheriting from there iter
class in the iterators
package. The iterator and its methods are not exported from the package. Here is the iterator and a test function in a script that is reproducible and runnable, the iterator is called pairsRef:
library(Biostrings)
library(iterators)
library(foreach)
setGeneric("maskSequences", function(object, seqnames, invert = TRUE, append = "union"){
standardGeneric("maskSequences")
})
setMethod("maskSequences",
signature("DNAMultipleAlignment", "character", "logical", "character"),
function(object, seqnames, invert, append) {
sequenceNames <- rownames(object)
rowmask(object, append = append, invert = invert) <-
which(sequenceNames %in% seqnames)
return(object)
})
pairsRef <- function(obj, ...){
UseMethod('pairsRef')
}
pairsRef.DNAMultipleAlignment <-
function(obj, ref = NULL, checkFun = function(x, ...) TRUE){
state <- new.env()
state$i <- 0L
state$obj <- obj
if(is.null(ref)){
state$ref <- rownames(obj)[1]
} else {
state$ref <- ref
}
state$nonRefs <- rownames(obj)
state$nonRefs <- state$nonRefs[state$nonRefs != state$ref]
it <- list(state=state, checkFun = checkFun)
class(it) <- c("pairsRef", "abstractiter", "iter")
return(it)
}
nextElem.pairsRef <- function(obj, ...){
repeat {
obj$state$i <- obj$state$i + 1L
if(obj$state$i > length(obj$state$nonRefs))
stop('StopIteration', call.=FALSE)
pair <- maskSequences(obj$state$obj,
c(obj$state$ref, obj$state$nonRefs[obj$state$i]),
invert = TRUE,
append = "replace"
)
if(obj$checkFun(pair)){
return(pair)
}
}
}
Test2 <- function(dna, ref){
pit <- pairsRef(dna, ref = ref, checkFun = function(x) TRUE)
results <- foreach(x = pit, .combine = c, .multicombine = TRUE) %do% {x}
return(results)
}
dna <-
readDNAMultipleAlignment(filepath =
system.file("extdata",
"msx2_mRNA.aln",
package="Biostrings"),
format="clustal")
Test2(dna, rownames(dna)[1])
However, I want to use this iterator to do foreach loops in a package of mine. If I put Test2 in a package (exported), and I have all the other functions in the package (unexported), and I have the package namespace import Biostrings, iterators, and foreach. It does not work. With a fresh R session, loading the package, and the running:
dna <-
Biostrings::readDNAMultipleAlignment(filepath =
system.file("extdata",
"msx2_mRNA.aln",
package="Biostrings"),
format="clustal")
Test2(dna, rownames(dna)[1])
Is this because the custom iterator is internal to the package? Any help or suggestions are greatly appreciated.
If I export the iterator and it's functions from the package. Then all works fine. But I don't necessarily want to export iterators of the package.
I have tried to look at the code for `%do%` in foreach, and have found `doSEQ` has.... environmenty stuff ... it gets called with parent.frame() and such on.
Has anyone else used custom iterators and foreach in their packages? How did you do it?
Many thanks,
Ben.
A test for your solution would be to ensure that the package works when it is loaded but not attached, for instance if the iterator were use in a function
foo()
then invoke foo without it being on the search path, in a new R sessionyourpkg::foo()
without first sayinglibrary(foo)
. This is how a package that Imports: your package would see foo().