Wednesday, April 23, 2014

Primitive R objects and functions by example

R primitives
# A name is just a tag by which we call objects,
# for example, a = 4, a is the name.
# In R, we have a name class, so when you evaluate a name object, you get its value.
# You can also create a name by a string, and then eval.
# The process is like: string "a" ... name a ... a

a = 15.1567
aname = as.name("a")
cat("class of aname: ", class(aname), "\n")
cat("string presentation of aname: ", aname, "\n")
cat("value of aname: ", eval(aname), "\n")

# You can also get a name obj by the quote function:

a = 15.1567
aname = quote(a)
cat("class of aname: ", class(aname), "\n")
cat("string presentation of aname: ", aname, "\n")
cat("value of aname: ", eval(aname), "\n")

# A call object is just an unevaluated call.
# It can be built from a list.
a = 15.1567
x = call("round", 15.1567)
y = call("round", quote(a))
is.call(x)
is.call(y)
for(i in seq(x)) {
    cat(i, ":  ")
    cat("class of x[[i]]: ", class(x[[i]]), "\n")
    cat("string presentation of x[[i]]: ", x[[i]], "\n")
}
for(i in seq(y)) {
    cat(i, ":  ")
    cat("class of y[[i]]: ", class(y[[i]]), "\n")
    cat("string presentation of y[[i]]: ", y[[i]], "\n")
}
print(eval(x))
print(eval(y))

# An expression is simply a sequence of calls
# you will find some similarity between expression and call:
a = 1
b = 2
x = expression(a + b)
y = call("+", a, b)
cat("Get the result by expression: ", eval(x), "\n")
cat("Get the result by call: ", eval(y), "\n")

# More formally, an expression is a call of the form
#     (f, a1, ..., an),
# which we normally read as
#     f(a1, ..., an).
# Here `x[[1]]` is equivalent to
#     (sin, a+b+1)
# or, more correctly,
#     (sin, (+, a, (+, b, 1))).
# Thus, `x[[1]][2]` returns
#     ((+, a, (+, b, 1)))
# (i.e. `(a+b+1)()` - no args!), and
# `x[[1]][[2]]` gives
#    (+, a, (+, b, 1)),
# i.e. `a+b+1`.

# A longer expression, with two calls
x = expression(sin(cos(a)))
for(i in seq(x)) {
    cat(i, ":  ")
    cat("class of x[[i]]: ", class(x[[i]]), "\n")
    cat("string presentation of x[[i]]: ", x[[i]], "\n")
}

x = 1
y = 2
z = 3
foo <- function(a, ...) {
    arg <- deparse(substitute(a))
    # dots <- substitute(list(...))[-1]
    dots <- substitute(list(...))
    print(class(dots))
    print(dput(dots))
    print(length(dots))
    for(i in seq(dots)) {
        print(class(dots[[i]]))
        print(dots[[i]])
    }
    # c(substitute(a), sapply(dots, deparse))
}
foo(x, y, z)

bar = function() {
    # for ordinary variable, its value is substituted
    # so basically, y = substitute(x) is equivalent to y = x
    x = 1.3
    y = substitute(x)
    print(class(y))
    print(y)
    # for ordinary variable, in this case a function, its value is substituted
    # so basically, y = substitute(x) is equivalent to y = x
    x = function() {cat("hihihi\n")}
    y = substitute(x)
    print(class(y))
    print(y)
    y()
}
bar()
# there is an exception for the above rule:
# in the global frame, the symbol is left unchanged
x = 1:3
y = substitute(x)
print(class(y))
print(eval(y))


f = function() cat("nobody\n")
bar = function(a = f) {
    # due to lazy evaluation, a is called a "promise object"
    # when a is a promise, substitute replaces it with its expression slot, i.e. f
    b1 = substitute(a)
    print(class(b1))
    b2 = eval(substitute(a))
    print(class(b2))
    b2()
}
bar()

0 comments: