{"action":"created","issue":{"url":"https://api.github.com/repos/matloff/partools/issues/2","labels_url":"https://api.github.com/repos/matloff/partools/issues/2/labels{/name}","comments_url":"https://api.github.com/repos/matloff/partools/issues/2/comments","events_url":"https://api.github.com/repos/matloff/partools/issues/2/events","html_url":"https://github.com/matloff/partools/issues/2","id":101050379,"number":2,"title":"More helper functions","user":{"login":"hadley","id":4196,"avatar_url":"https://avatars.githubusercontent.com/u/4196?v=3","gravatar_id":"","url":"https://api.github.com/users/hadley","html_url":"https://github.com/hadley","followers_url":"https://api.github.com/users/hadley/followers","following_url":"https://api.github.com/users/hadley/following{/other_user}","gists_url":"https://api.github.com/users/hadley/gists{/gist_id}","starred_url":"https://api.github.com/users/hadley/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hadley/subscriptions","organizations_url":"https://api.github.com/users/hadley/orgs","repos_url":"https://api.github.com/users/hadley/repos","events_url":"https://api.github.com/users/hadley/events{/privacy}","received_events_url":"https://api.github.com/users/hadley/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":1,"created_at":"2015-08-14T16:41:43Z","updated_at":"2015-08-16T16:39:16Z","closed_at":null,"body":"I think the code in partools could be made substantially more elegant with a few helper functions:\r\n\r\n```R\r\nclusterRequireNamespace <- function(cl, pkg) {\r\n  clusterCall(cl, requireNamespace, package = pkg, quietly = TRUE)\r\n}\r\nclusterRequirePackage <- function(cl, pkg) {\r\n  clusterCall(cl, library, package = pkg, character.only = TRUE)\r\n}\r\nclusterEval < function(cl, expr) {\r\n  clusterCall(cl, eval, expr, env = .GlobalEnv)\r\n}\r\n\r\nclusterAssign <- function(cl, name, value) {\r\n  clusterCall(cl, assign, x = name, value = value)\r\n}\r\n\r\nasCall <- function(x) {\r\n  if (inherits(x, \"formula\")) {\r\n    stopifnot(length(x) == 2)\r\n    x[[2]]\r\n  } else if (is.atomic(x) || is.name(x) || is.call(x)) {\r\n    x\r\n  } else {\r\n    stop(\"Unknown input\")\r\n  }\r\n}\r\n\r\nclusterEvalI <- function(cl, expr, ...) {\r\n  args <- lapply(list(...), asCall)\r\n  interpolated <- methods::substituteDirect(asCall(expr), args)\r\n  \r\n  clusterEval(cl, interpolated)\r\n}\r\n```\r\n\r\nThis allows (e.g.) `fileread` to be rewritten as:\r\n\r\n```R\r\n\r\nfileread <- function (cls, fname, dname, ndigs, header = FALSE, sep = \" \", \r\n                      usefread = FALSE) {\r\n  if (usefread) {\r\n    clusterRequireNamespace(cls, \"data.table\")\r\n    clusterEvalI(cls, ~ myfread <- data.table::fread))\r\n  } else {\r\n    clusterEvalI(cls, ~ myfread <- read.table))\r\n  }\r\n  \r\n  clusterEvalI(cl,\r\n    ~ `_mychunk` <- filechunkname(fname, ndigs), \r\n    fname = fname, ndig\r\n    s = ndgs\r\n  )\r\n\r\n  clusterEvalI(cls,\r\n    ~ dname <- myfread(`_mychunk`, header = header, sep = sep),\r\n    dname = as.name(dname),\r\n    header = header,\r\n    sep = sep\r\n  )\r\n}\r\n```\r\n\r\nwhich I think is rather more clear since it focusses on the computation, rather than the details of the call manipulation (and working with the AST is obviously more elegant than working with strings)\r\n\r\n(Also note the use of `_mychunk` as a variable name - using a non syntactic variable should decrease the chances of accidentally clobbering an object that the user created)\r\n\r\nI haven't tested this code yet, but I'm happy to do so if you're interested in the idea."},"comment":{"url":"https://api.github.com/repos/matloff/partools/issues/comments/131579901","html_url":"https://github.com/matloff/partools/issues/2#issuecomment-131579901","issue_url":"https://api.github.com/repos/matloff/partools/issues/2","id":131579901,"user":{"login":"matloff","id":7585381,"avatar_url":"https://avatars.githubusercontent.com/u/7585381?v=3","gravatar_id":"","url":"https://api.github.com/users/matloff","html_url":"https://github.com/matloff","followers_url":"https://api.github.com/users/matloff/followers","following_url":"https://api.github.com/users/matloff/following{/other_user}","gists_url":"https://api.github.com/users/matloff/gists{/gist_id}","starred_url":"https://api.github.com/users/matloff/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/matloff/subscriptions","organizations_url":"https://api.github.com/users/matloff/orgs","repos_url":"https://api.github.com/users/matloff/repos","events_url":"https://api.github.com/users/matloff/events{/privacy}","received_events_url":"https://api.github.com/users/matloff/received_events","type":"User","site_admin":false},"created_at":"2015-08-16T16:39:16Z","updated_at":"2015-08-16T16:39:16Z","body":"Thanks, I'll look into this. Actually, there are lots of ways in which the code could be made more elegant. :-)"}}