Created
June 26, 2011 16:02
-
-
Save yatsuta/1047733 to your computer and use it in GitHub Desktop.
Lisp by R
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
opt <- options(warn=-1) | |
## ------------------------------------------------------------ | |
## Test | |
## ------------------------------------------------------------ | |
## > rm(list=ls()); source("Eval.R") | |
## > repl() | |
## rlisp > (<- make.counter (function (c) (function () (<<- c (+ c 1))))) | |
## <Closure Function Sexp> | |
## rlisp > (<- c1 (make.counter 3)) | |
## <Closure Function Sexp> | |
## rlisp > (c1) | |
## <Number Sexp: 4.000000> | |
## rlisp > (c1) | |
## <Number Sexp: 5.000000> | |
## rlisp > (c1) | |
## <Number Sexp: 6.000000> | |
## rlisp > (<- c2 (make.counter 100)) | |
## <Closure Function Sexp> | |
## rlisp > (c2) | |
## <Number Sexp: 101.000000> | |
## rlisp > (c2) | |
## <Number Sexp: 102.000000> | |
## rlisp > (c2) | |
## <Number Sexp: 103.000000> | |
## rlisp > (c1) | |
## <Number Sexp: 7.000000> | |
## rlisp > | |
## ------------------------------------------------------------ | |
## S Expressions and Env | |
## ------------------------------------------------------------ | |
Num <- function(num.value) { | |
obj <- list(num.value=num.value) | |
class(obj) <- c("Num", "Sexp") | |
obj | |
} | |
## Str <- function(str.value) { | |
## obj <- list(str.value=str.value) | |
## class(obj) <- c("Str", "Sexp") | |
## obj | |
## } | |
Symbol <- function(symbol.value) { | |
obj <- list(symbol.value=symbol.value) | |
class(obj) <- c("Symbol", "Sexp") | |
obj | |
} | |
Closure <- function(formals, body, env) { | |
obj <- list(formals=formals, body=body, env=env) | |
class(obj) <- c("Closure", "Sexp") | |
obj | |
} | |
Primitive <- function(primitive.fun) { | |
obj <- list(primitive.fun=primitive.fun) | |
class(obj) <- c("Primitive", "Sexp") | |
obj | |
} | |
Env <- function(frame, parent) { | |
obj <- dict() | |
obj$frame <- frame | |
obj$parent <- parent | |
class(obj) <- "Env" | |
obj | |
} | |
## ------------------------------------------------------------ | |
## S Expressions Print Fucntions | |
## ------------------------------------------------------------ | |
toString.Num <- function(sexp) sprintf("<Number Sexp: %f>", sexp$num.value) | |
## toString.Str <- function(sexp) sprintf("<String Sexp: '%s'>", sexp$str.value) | |
toString.Symbol <- function(sexp) sprintf("<Symbol Sexp: %s>", sexp$symbol.value) | |
toString.Closure <- function(sexp) "<Closure Function Sexp>" | |
toString.Primitive <- function(sexp) "<Primitive Function Sexp>" | |
toString.list <- function(list) { | |
paste("[", do.call("paste", c(lapply(list, toString), sep=", ")), "]", sep="") | |
} | |
print.Sexp <- function(sexp) print(toString(sexp)) | |
## ------------------------------------------------------------ | |
## my.parse | |
## ------------------------------------------------------------ | |
read <- function(program.text) { | |
read.from(tokenize(program.text))$value | |
} | |
my.parse <- read | |
tokenize <- function(program.text) { | |
strsplit(gsub("\\)", " )", gsub("\\(", "( ", program.text)), "\\s+")[[1]] | |
} | |
read.from <- function(tokens) { | |
if (length(tokens) == 0) stop("unexpected EOF") | |
token <- tokens[[1]] | |
tokens <- tokens[-1] | |
if (token == "(") { | |
l <- list() | |
while (tokens[[1]] != ")") { | |
read.result <- read.from(tokens) | |
value <- read.result$value | |
tokens <- read.result$tokens | |
if (mode(value) == "list") value <- list(value) | |
l <- append(l, value) | |
} | |
tokens <- tokens[-1] | |
list(value=l, tokens=tokens) | |
} else if (token == ")") { | |
stop("unexpected ')'") | |
} else { | |
list(value=sexp(token), tokens=tokens) | |
} | |
} | |
sexp <- function(token) { | |
if (!is.na(as.double(token))) | |
Num(as.double(token)) | |
else | |
Symbol(token) | |
} | |
## ------------------------------------------------------------ | |
## my.eval | |
## ------------------------------------------------------------ | |
my.eval <- function(exp, ...) UseMethod("my.eval", exp) | |
my.eval.Num <- function(exp, env) exp | |
## my.eval.Str <- function(exp, env) exp | |
my.eval.Symbol <- function(exp, env) lookup.env(env, exp$symbol.value) | |
my.eval.Closure <- function(exp, env) exp | |
my.eval.Primitive <- function(exp, env) exp | |
my.eval.list <- function(exp, env) { | |
op <- exp[[1]] | |
args.exp <- exp[-1] | |
if (inherits(op, "Symbol") && op$symbol.value == "<-") { | |
var.exp <- args.exp[[1]] | |
val.exp <- args.exp[[2]] | |
if (!inherits(var.exp, "Symbol")) stop(var.exp, " is not a symbol.") | |
define(env, var.exp$symbol.value, my.eval(val.exp, env)) | |
} else if (inherits(op, "Symbol") && op$symbol.value == "<<-") { | |
var.exp <- args.exp[[1]] | |
val.exp <- args.exp[[2]] | |
if (!inherits(var.exp, "Symbol")) stop(var.exp, " is not a symbol.") | |
deep.define(env, var.exp$symbol.value, my.eval(val.exp, env)) | |
} else if (inherits(op, "Symbol") && op$symbol.value == "function") { | |
formals <- args.exp[[1]] | |
body <- args.exp[[2]] | |
Closure(formals, body, env) | |
} else if (inherits(op, "Symbol") && op$symbol.value == "if") { | |
cond <- args.exp[[1]] | |
true.clause <- args.exp[[2]] | |
false.clause <- args.exp[[3]] | |
if (my.eval(cond, env)$num.value == 0) { | |
my.eval(false.clause, env) | |
} else { | |
my.eval(true.clause, env) | |
} | |
} else { | |
call.fun(my.eval(op, env), each.my.eval(args.exp, env)) | |
} | |
} | |
each.my.eval <- function (exp.list, env) { | |
lapply(exp.list, function(exp) my.eval(exp, env)) | |
} | |
## ------------------------------------------------------------ | |
## Utilities | |
## ------------------------------------------------------------ | |
dict <- new.env | |
my.cat <- function(...) do.call("cat", lapply(list(...), toString)) | |
lookup.env <- function(env, var) { | |
if (is.null(env)) stop(var, " not found.") | |
if (var %in% names(env$frame)) { | |
env$frame[[var]] | |
} else { | |
lookup.env(env$parent, var) | |
} | |
} | |
define <- function(env, var, val) { | |
env$frame[[var]] <- val | |
val | |
} | |
deep.define <- function(env, var, val) { | |
if (is.null(env$parent)) { | |
env$frame[[var]] <- val | |
val | |
} else if (var %in% names(env$parent$frame)) { | |
env$parent$frame[[var]] <- val | |
val | |
} else { | |
deep.define(env$parent, var, val) | |
} | |
} | |
call.fun <- function(fun, args) { | |
if (inherits(fun, "Closure")) { | |
formals <- fun$formals | |
body <- fun$body | |
env <- fun$env | |
my.eval(body, extend.env(env, formals, args)) | |
} else { | |
fun$primitive.fun(args) | |
} | |
} | |
extend.env <- function(env, formals, args) { | |
frame <- list() | |
if (length(formals) == 0) { | |
Env(frame=frame, parent=env) | |
} else { | |
for (i in 1:length(formals)) { | |
name <- formals[[i]]$symbol.value | |
value <- args[[i]] | |
frame[[name]] <- value | |
} | |
Env(frame=frame, parent=env) | |
} | |
} | |
repl <- function(env=default.env, prompt="rlisp > ") { | |
while(TRUE) { | |
cat(prompt) | |
val <- my.eval(my.parse(readline()), env) | |
my.cat(val, "\n") | |
} | |
} | |
## ------------------------------------------------------------ | |
## Primitive Fucntions | |
## ------------------------------------------------------------ | |
add <- Primitive(function(args) { | |
x <- args[[1]]; y <- args[[2]] | |
Num(x$num.value + y$num.value) | |
}) | |
sub <- Primitive(function(args) { | |
x <- args[[1]]; y <- args[[2]] | |
Num(x$num.value - y$num.value) | |
}) | |
mult <- Primitive(function(args) { | |
x <- args[[1]]; y <- args[[2]] | |
Num(x$num.value * y$num.value) | |
}) | |
div <- Primitive(function(args) { | |
x <- args[[1]]; y <- args[[2]] | |
Num(x$num.value / y$num.value) | |
}) | |
## join.str <- Primitive(function(args) { | |
## x <- args[[1]]; y <- args[[2]] | |
## Str(paste(x$str.value, y$str.value, sep="")) | |
## }) | |
eq <- Primitive(function(args) { | |
x <- args[[1]]; y <- args[[2]] | |
if (x$num.value == y$num.value) Num(1) else Num(0) | |
}) | |
gt <- Primitive(function(args) { | |
x <- args[[1]]; y <- args[[2]] | |
if (x$num.value > y$num.value) Num(1) else Num(0) | |
}) | |
lt <- Primitive(function(args) { | |
x <- args[[1]]; y <- args[[2]] | |
if (x$num.value < y$num.value) Num(1) else Num(0) | |
}) | |
## ------------------------------------------------------------ | |
## default.env | |
## ------------------------------------------------------------ | |
default.env <- Env(list("TRUE"=Num(1), | |
"FALSE"=Num(0), | |
"+"=add, | |
"-"=sub, | |
"*"=mult, | |
"/"=div, | |
## "++"=join.str, | |
"="=eq, | |
">"=gt, | |
"<"=lt), NULL) | |
## options(opt) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment