Hacker News new | ask | show | jobs
by klibertp 754 days ago
Thanks for a great explanation. It looks like the thing Scala does with its by-name parameters, but for every parameter by default. Even closer analogy, I think Io works in a very similar way - bodies of methods can access their arguments as Message (ie. unevaluated calls) objects and then decide to evaluate them as needed (which differs from your example in that the body can choose the context in which the message send is to be executed, it doesn't have to be lexical scope of a caller). It enables a great deal of expressivity - esp. coupled with some syntactic sugar for "operators" - and I always wondered why more languages don't have that feature.
2 comments

In R, you can also choose the context in which the argument expression is to be evaluated. If you just use the promise as if it were a value and rely on implicit evaluation, then it happens in the context of the caller, yes. But environments (i.e. sets of name-value bindings) in R are first-class objects, so they can be captured at any given point, and later used to explicitly evaluate promises after retrieving the latter's associated expression.

   foo <- function(x, env) {
     print(x);  # implicit eval
     
     x_expr <- substitute(x);  # gets the associated expression
     print(eval(x_expr, env));  # explicit eval in different environment
   }

   bar <- function(y) {
     environment()  # capture and return local environment of function
   }

   y <- 1
   env <- bar(2);
   foo(y * y, env);  # prints 1 then 4.
Side note: substitute() seems like a weird name for a function that returns the underlying expression of the promise. It's named that way because it's actually similar in intended use to quasiquotation - it lets you explicitly substitute variable names for something else in the expression before evaluating it. So e.g. substitute(x <- x + 1, x=2) returns the expression object for (1 <- 1 + 2). Not passing any named arguments is just a special case where no substitutions are made and the original expression is returned instead, although in practice that is probably the most common way to use it.
Oh, I loved using Io in the late 2000s (and did all my algorithms assignments in it, probably to the chagrin of the instructor who allowed us to use any language we wanted). Maybe that explains some of my affinity toward R. Is there anything else useful that is similar to it these days?