LINUX.ORG.RU

Метацикл

 


0

2

До меня наконец дошло, что ЭТО такое НА САМОМ ДЕЛЕ. Написал игрушечный интерпретатор, который считывает строки и эвалит их следующим образом. Есть некий неймспейс, куда добавлены некоторые определения. Если это определение есть в неймспейсе, то на вывод подается значение этого определения, а если нет — эвалится нативным эвалом. Фишка в том, что прямо из интерактивной сессии можно добавлять определения в неймспейс. Например, что-то типа

a
>>>error: no such variable
addToNamespace("a", "1")
>>>ok
a
>>>1
Мы расширили синтаксис прямо изнутри интерактивной сессии, безо всяких костылей, макросов, и даже фэкспры не нужны!

вот он, настоящий метацикл! Тот интерпретатор лиспа, который приводится в SICP — это не метациклический интерпретатор, это просто интерпретатор лиспа, написанный на лиспе. Ну, или то что я накалякал, это не просто метациклический интерпретатор, а «волшебный интерпретатор». Что-то одно из двух.

terminator-101, ты ли это?

anonymous
()

«волшебный интерпретатор»

Быстрей патентуй.

Deleted
()

Мы расширили синтаксис

добавить значение в неймспейс - это уже расширить синтаксис?

x4DA ★★★★★
()

Я заважу свой метаци-ы-ыкл.

anonymous
()
Ответ на: комментарий от Weres

Вот он! Вон он, наглядный пример полезности буквы ё!

nanoolinux ★★★★
()

волшебный интерпретатор

Отличная характеристика для тебя самого.

anonymous
()
Ответ на: комментарий от J-yes-sir
> (setq |foo bar baz| 1)
> |foo bar baz|
1
> (princ |foo bar baz|)
foo bar baz
> let foo_bar_baz = 1
> foo_bar_baz
1
> let foo'bar'baz = 1
> foo'bar'baz
1
> ht <- new
> insert ht "foo bar baz" 1
> lookup ht "foo bar baz"
1
data Add = Add String Int deriving Read

loop = do
  ht <- new
  forever $ do
    cmd <- getLine
    case reads cmd of
      [(Add k v, _)] -> insert ht k v
      _ -> print =<< lookup ht cmd
> loop
a
Nothing
Add "a" 1
a
Just 1
foo bar baz
Nothing
Add "foo bar baz" 1
foo bar baz
Just 1
motto
()

волшебный интерпретатор

сказочный терминатор

легендарный вибратор^W^W

anonymous
()
Ответ на: комментарий от mix_mix

Поздравляю, ты переизобрел term rewriting system.

Все в Mathematica! :)

motto
()

anonimous вернулся. Можешь снова уходить.

Aswed ★★★★★
()
Ответ на: комментарий от anonymous

И в чем разница между его примером и твоим?

В том, что на вход я принимаю произвольную строку, и, после небольшого допила, произвольным образом ее обрабатываю

J-yes-sir
() автор топика

волшебный интерпретатор -> сказочный интерпретатор -> сказочный долб**б

Aswed ★★★★★
()

Скоро тебя, убогого шизофреника, опять забанят.

anonymous
()

Не знаю, что ты там расширил, но в твоем примере просто определяется переменная «a» со значением 1.

>>> a = 1 # мы расширили синтаксис!
>>> def b(): return a # и мы опять сделали это!
Virtuos86 ★★★★★
()

«Дзен и искусство ухода за метациклом»

stevejobs ★★★★☆
()
Ответ на: комментарий от J-yes-sir

Мы добавляем правило для обработки входной строки.

Это называется reader macro. Хотя в твоем примере никакого reader macro нет, ты просто создаешь переменную.

P.S. не знаю зачем я отвечаю этому сумасшедшему.

grouzen ★★
()

Мы расширили синтаксис прямо изнутри интерактивной сессии

Ааа я ето а порнухе какой-то видал. Хм, не помню, блин, название..

anonymous
()

Волшебный код в студию!

omich
()
Ответ на: комментарий от J-yes-sir

О БОЖЕ У ПЕРЕМЕННОЙ МОГУТ БЫТЬ ПРОБЕЛЫ В ИМЕНИ.

Kuzy ★★★
()
Ответ на: комментарий от J-yes-sir
add("foo bar baz" "1")
[quote][quote][quote]ok[br][/quote][/quote][/quote]foo bar baz
[quote][quote][quote]1[br][/quote][/quote][/quote]add("add(\"baz bar foo\", \"1\")" "1")
[quote][quote][quote]ok[br][/quote][/quote][/quote]add("baz bar foo" "1")
[quote][quote][quote]1[br][/quote][/quote][/quote]baz bar foo
[quote][quote][quote]error: no such variable[br][/quote][/quote][/quote]
anonymous
()
Ответ на: комментарий от anonymous
add("foo bar baz" "1")
>>>ok
foo bar baz
>>>1
add("add(\"baz bar foo\", \"1\")" "1")
>>>ok
add("baz bar foo" "1")
>>>1
baz bar foo
>>>error: no such variable
anonymous
()
Ответ на: комментарий от J-yes-sir

все работает

Запости реализацию — посмотреть что ты там открываешь, ассоциативные массивы, циклы с I/O или лексический разбор.

motto
()
Ответ на: комментарий от motto

Я щас допиливаю, но изначальная, реализация, самый простой вариант, прост до безобразия.(JS)

add=function(name, value){
   namespace[name]=value
}

var readline = require('readline');

var rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  terminal: false
});

namespace={}
rl.on('line', function (cmd) {
  var out=namespace[cmd]||(function(){try{return eval(cmd)}catch(e){return cmd}}())
  console.log('>>> '+out);
});
То есть, это обычный repl. если сверху запилить свой эвал, строки будут обрабатываться произвольным образом. Я пытаюсь щас добиться, того, чтобы сам эвал можно было расширять интерактивно.

J-yes-sir
() автор топика
Ответ на: комментарий от J-yes-sir

У тебя там замена по РЕГЕКСПАМ, да? Запили Си-препроцессор для js. Еще более волшебно.

Kuzy ★★★
()
Ответ на: комментарий от J-yes-sir

Лол, реально почти Си-препроцессор. Замени строчки на токены (забей на пробелы). Тогда будет полущ.

Kuzy ★★★
()

норкоман, ты опять выходишь на связь?

lazyklimm ★★★★★
()
Ответ на: комментарий от J-yes-sir

add(«a», 1) => undefined; a => 1; a + 1 => a + 1.

Ты к нативному окружению добавил свой namespace, но нативный eval про него не знает, так что ничего не работает. Значит писать свой eval? Разница только в том, что у тебя в namespace произвольные строки, тогда как в нативном — стандартные имена (без пробелов и т.п.). Не велика разница.

$ node
> a = 1
1
> a
1
> a + 1
2
rl = require("readline").createInterface
  input: process.stdin
  output: process.stdout
  terminal: false

rl.on "line", (cmd) -> console.log try eval cmd catch _ then cmd
%^B#&
%^B#&
a
a
a + 1
a + 1
a = 1
1
a
1
a + 1
2

В чём вообще затея? Выше сказали про term-rewriting, ну и символьные вычисления туда же, когда «a + b» вычисляется в «a + b» если a и b не заданы более явно, а «a + a» вычисляется в «2 a» (a не задан). http://en.wikipedia.org/wiki/Wolfram_Language. Выше если «a + b» => «a + b», потом «a = 1» — «a + b» не редуцируется до «1 + b», нативный eval не потянет.

motto
()
Ответ на: комментарий от motto

Значит писать свой eval?

Ну да, конечно. Вот примитивный вариант

first=function(str){return str.split(" ")[0]}
rest=function(str){return str.split(" ").slice(1).join(" ")}
getFirst=function(x){return x.match(/(.*);/)[1]}
getSecond=function(x){return x.match(/;(.*)/)[1]}

isCall=function(expr){
   return first(expr)==="call"
}
add=function(name, value){
   namespace[name]=value
}

var readline = require('readline');

var rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  terminal: false
});

namespace={}
erules={

}
Eval=function(expr){
   if(isCall(expr)) return eval((rest(getFirst(expr)))).call(this, eval(getSecond(expr)))
   try{return eval(expr)}catch(e){return expr}
}

rl.on('line', function (cmd) {
//  var out=namespace[cmd]||(function(){try{return eval(cmd)}catch(e){return cmd}}())
  var out=namespace[cmd]||Eval(cmd)
  console.log('>>> '+out);
});
работает примерно так,
f=function(){return x+x}
>>>function
f(1)
>>>2
call f ; 1
>>>2
то есть, такого синтаксиса, как в последней строчке, в source языке нет, мы его привнесли. Но это пока мы только расширили синтаксис путем правки исходника вычислителя.

В чём вообще затея?

Эти правила обработки строк, в принципе, можно делать и из нижнего языка. Вот в этом. В расширении вычислителя изнутри языка.

J-yes-sir
() автор топика
Ответ на: комментарий от J-yes-sir

add(«a», 1) => undefined; a => 1; a + 1 => a + 1.

Не решено. С нуля надо писать — лексический и синтаксический разбор, интерпретатор дерева, REPL, всё с фидбеком (он обычно есть в любом лиспе, в SBCL, например — расширяй/меняй изнутри образа (почти) что угодно как хочешь, только никому не показывай, разумеется :)).

З.Ы. http://github.com/airbnb/javascript

motto
()
Ответ на: комментарий от Oxdeadbeef

Отпишись, тут лисперов нет. (Единственное, мне только Zubok помогал)

niemand
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.