consを利用した言語の実装
とりあえず、四則演算+if文が使えるxxx言語を実装してみました。javascriptで。
[if, [=,[+,1,2],4],111, 222] if[=[+[1,2],4],111,222] if (=[+[1,2],4]) [111,222] if (= (+[ 1, 2]) 4 []) 111 222 [] if (= (+ 1 2 []) 4 []) 111 222 [] (if (= (+ 1 2 []) 4 []) 111 222 [])
これらは全て同じ意味で、
JavaScriptやらC言語だと
(1+2 == 4) ? 111 : 222
Lispだと
(if (= (+ 1 2) 4) 111 222)
の意味になります。いちお、Lispとは違う式指向言語になっております。
こういった言語が他にないのか知りたいところです。
どっかにあっていいと思うのだけど。
追記
最終的に変換してくると、S式にとても似ている。
(if (= (+ 1 2 []) 4 []) 111 222 []) (if (= (+ 1 2) 4) 111 222)
が同じ意味となるようにしたら、S式の自然な拡張にできて、
いいのではないかという風に思います。
さらに追記&修正
[]は;であるとする。するとすると、、、。
if (= (+ 1 2;) 4;) 111 222; if (=[+[1,2],4]) 111 222;
なんて書けて、
[if, [=,[+,1,2],4],111, 222] if[=[+[1,2],4],111,222] if (=[+[1,2],4]) [111,222] if (= (+[ 1, 2]) 4 []) 111 222 [] if (= (+ 1 2 []) 4 []) 111 222 [] (if (= (+ 1 2 []) 4 []) 111 222 []) (if (= (+ 1 2 ;) 4 ;) 111 222 ;) if (= (+ 1 2;) 4;) 111 222; if (=[+[1,2],4]) 111 222;
と言った具合になるぞと。おお、凄いかもしれないし、凄くないかもしれない。
以下ソース
<script> var nil = [null, null]; function sexp(str) { var pop = function() { str = str.replace(/^ +/,""); var s = str.charAt(0); str = str.substring(1); return s; }; var peek = function() { str = str.replace(/^ +/,""); return str.charAt(0); }; var cons = function() { document.write("cons "+str+"<br>"); var c = atom(); if (peek() != "." && peek() != "" && peek() != "," && peek() != "]"&& peek() != ")") { c = [c, cons()]; } document.write("ret cons "+c+"<br>"); return c; } var atom = function() { document.write("atom "+str+"<br>"); var c = peek(); if (c == ";") { pop(); return [null,null]; } if (c == "(") { pop(); c = cons(); if (pop() != ")") throw "error ] ... ["+str+"]"; return c; } if (c == "[") { pop(); c = paren(); if (pop() != "]") throw "error ] ... ["+str+"]"; return c; } if (c == "\"") { var s = str.match(/^"[^"]+"/); return s.substring(1, s.length - 1); } if (c.match(/^[0-9]/)) { var s = str.match(/^[0-9]+/); str = str.substring(s[0].length); return Number(s[0]); } if (c.match(/^[^\r\n\t\:\, ]/)) { var s = str.match(/^[^\r\n\t\]\[\:\,\(\) ]+/); document.write(str+"<br>"); str = str.substring(s[0].length); document.write(">"+str+"<br>"); if (s[0] == "NIL") return nil; return s[0]; } // document.write("["+c + "]...[" + str + "]<br>"); throw "error atom" + str; } var paren = function() { // document.write("paren "+str+"<br>"); if(peek() == "]") return [null, null]; var c = cons(); if (peek() == "]") return [c, [null,null]]; if (peek() == "...") { pop(); return [c, cons()]; } if (peek() == ",") { pop(); return [c, paren()]; } return c; }; return cons(); } //try{ // alert(sexp("(12 13)")); //} catch (e) {alert(e);} function isNil(l) { return (l[0] == null) && (l[1] == null); } // リスト表示 function p2(e) { var s1 = ""; if (e[0] instanceof Array) { s1 = p(e[0]); } else { s1 = e[0] + ""; } if (e[1] instanceof Array) { if (isNil(e[1])) return s1; return s1 + " " + p2(e[1]); } return s1 + " . "+ e[1]; } function p(e) { aaaacnt++; if(aaaacnt > 100) return " ... overflow ..."; if (e instanceof Array) { if (isNil(e)) return "nil"; return "("+p2(e)+")"; } return "" + e; } //alert(p([[1,2],[1,nil]])); Array.prototype.toString = function() { aaaacnt = 0; return p(this); } // Arrayをリストに変換する。 // [1, 2, 3] -> [1 ,[2, [3, nil]]] function list(a) { if (typeof(a) == "object" && a.length != null) { var r = nil; if (a.length >= 3 && a[a.length - 2] == ".") { r = [a[a.length - 3], a[a.length - 1]]; a.length -= 3; } for (var i = a.length - 1; i >= 0; i--) r = [list(a[i]), r]; return r; } return a; }; var car = function (r) { return r[0]; }; var cdr = function (r) { return r[1]; }; var cons = function (a, b) { return [a, b]; }; var replcar = function (a, b) { a[0] = b; return a; }; function caar(l) { return car(car(l)); } function cadr(l) { return car(cdr(l)); } function cdar(l) { return cdr(car(l)); } function cddr(l) { return cdr(cdr(l)); } function caddr(l) { return car(cdr(cdr(l))); } function cadddr(l) { return car(cdr(cdr(cdr(l)))); } function caddddr(l) { return car(cdr(cdr(cdr(cdr(l))))); } function eval(p, env) { if (!isNaN(p))return p; if (p instanceof Array) {// 関数適用 switch (car(p)) { case "+": return eval(cadr(p), env) + eval(caddr(p), env); case "-": return eval(cadr(p), env) - eval(caddr(p), env); case "*": return eval(cadr(p), env) * eval(caddr(p), env); case "/": return eval(cadr(p), env) / eval(caddr(p), env); case "=": return eval(cadr(p), env) == eval(caddr(p), env); case "if": return eval(cadr(p), env) ? eval(caddr(p), env) : eval(cadddr(p), env); } var envs = getEnv(p[0], env); return eval(e, envs[1]); } var envs = getEnv(p, env); return eval(envs[0], envs[1]); } function getEnv(p, env) { while (env != null) { if (env[p] != null) return [env[p], env]; env = env["parent"]; } } //alert(eval(sexp("(if (= (+ 1 2) 4) 111 222)"))); alert(eval(sexp("[if, [=,[+,1,2],4],111, 222]"))); alert(eval(sexp("if[=[+[1,2],4],111,222]"))); alert(eval(sexp("if (=[+[1,2],4]) [111,222]"))); alert(eval(sexp("if (= (+[ 1, 2]) 4 []) 111 222 []"))); alert(eval(sexp("if (= (+ 1 2 []) 4 []) 111 222 []"))); alert(eval(sexp("(if (= (+ 1 2 []) 4 []) 111 222 [])"))); alert(eval(sexp("if (= (+ 1 2;) 4;) 111 222;"))); alert(eval(sexp("if (=[+[1,2],4]) 111 222;"))); </script>