Post 6: Refactoring Part II: a generic proposal function

[This article was first published on Markov Chain Monte Carlo in Item Response Models, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

In this post we refactor the proposal function from the previous post into a generic normal proposal function. This allows us to implement normal proposals for the (yet to be developed) samplers for the item parameters without duplicating code.

Our approach is to write a function which returns a function. We begin with a toy example to explain why that would work, implement a function that returns a normal proposal function, and then check that the refactored function works.

The toy example

Writing functions that return functions sounds strange. Here we give a toy example to explain how it works.

Pretend that we want to write two similar functions for comparing numbers:

## A function to check if the parameter is less than three

R is designed to allow us to make a function which can build other functions. For example, we can make an “is X less than” function that takes X as a variable and returns a function like the is.three.less.than function above:

## We can write a function in R to build those other functions

Now we can use is.X.less.than to define our functions from before, which still work the same:

## Define them

For the curious: Why does that even work?

This works because functions in R are implemented as a kind of paired object called a closure. A closure contains both the “text” of the function to be run and an “environment” which can contain additional variables.

In the example above, the is.X.less.than function returned a closure which contained both the “text” of function( b.value ) { return( X < b.value )} and the value of X. To see this for our example, we simply call the generated is.three.less.than function without parenthesis:

## function( b.value ) {
##              return( X < b.value )
##           }
## < environment: 0x3489ee8 >

And peek inside the environment with the ls(...) function, to see that it does contain X:

ls( envir=environment(is.three.less.than) )
## [1] "X"

And even see what X is set to in the environment of is.three.less.than:

## [1] 3

Similarly, for the other function, we get

## [1] 2

as expected.

A function to return a proposal function

Recall that in post 5 we defined the person ability proposal function to be:

## Proposal function for the person ability parameters 

If we were okay with duplicating the code, we could copy the text of and change all of the names from depending on th to depending on the name of the other parameter (e.g. a).

Instead, we shall write a function which takes the name of the parameter as a variable and returns the equivalent function. Here we interleave comments for what the person ability version would have been:

## Write a function to return a proposal function for that parameter

Then implementing the refactored proposal function is simple: 

Testing the refactored code

Here we see if the sampler will produce the same output with the refactored code in place.

## Load the necessary code from this and previous posts

## Check that we have the version from Post 4. 
## 1 function (state)                                                
## 2 {                                                               
## 3     th.old 

That the output is identical suggests that the code was refactored correctly.

To leave a comment for the author, please follow the link and comment on their blog: Markov Chain Monte Carlo in Item Response Models. offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)