Question

I am trying to figure out the conceptual implications of providing a functional user interface to reference classes (or indeed S4/S3 classes). In short, I am concerned that if I write code that looks like as below, then it is equivalent to writing functional code.

Here is a simple linear regression class:

linRegClass = setRefClass('linRegClass',
                          fields = list(formulaReg = 'formula',
                                        dataReg = 'data.frame'),
                          methods = list(doReg = function() {
                            lm(.self$formulaReg, data = .self$dataReg)
                          }))

linRegInstance = linRegClass$new(dataReg = cars, 
                    formulaReg = as.formula(speed ~ dist))
linRegInstance$doReg()
class(linRegInstance)

The object-oriented interface is not very user friendly, so as in Martin Morgan's slides, I will write a functional user interface for the underlying reference class:

fnLinReg = function(formulaReg, dataReg) {
  linRegInstance = linRegClass$new(formulaReg = formulaReg, 
                                   dataReg = dataReg)
  linRegInstance$doReg()
}

## use the functional interface
fnLinReg(dataReg = cars, formulaReg = as.formula(speed ~ dist))

Now this functional interface is observationally equivalent to a purely functional

fnLinReg2 = function(formulaReg, dataReg) {
  lm(formula = formulaReg, data = dataReg)
}

## use the pure function
fnLinReg2(dataReg = cars, formulaReg = as.formula(speed ~ dist))

I am trying to figure out whether this is because my example is pathologically simple, but I still wonder if there is any point in writing reference classes and then wrapping them in functional interfaces versus writing purely functional code.

Any detailed examples would help greatly.

Était-ce utile?

La solution

Complicated constructors can be defined using the initialize method, which will automatically be called when you call new. I've modified your example to contain the initialize method, and a new field to store the regression result, because initialize will always return the referenceClass:

linRegClass = setRefClass('linRegClass',
                          fields = list(formulaReg = 'formula',
                                        dataReg = 'data.frame',
                                        result = 'lm'),
                          methods = list(doReg = function() {
                            lm(.self$formulaReg, data = .self$dataReg)
                          },
                          initialize = function(formulaReg, dataReg, ...) {
                            formulaReg <<- formulaReg
                            dataReg <<- dataReg
                            result <<- .self$doReg()
                          }))

So now we simply have:

linRegInstance <- linRegClass$new(dataReg = cars, 
                                    formulaReg = as.formula(speed ~ dist))
linRegInstance$result
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top