Ниже приведена имплементация JsonT (json transformation) в TIScript.
В качестве идеи использовалась http://goessner.net/articles/jsont/
Проблема с имплементацией оного в JavaScript состоит в том что Stefan Goessner использовал eval() и regular expressions.
Что в общем-то накладно при массивном использовании. (Я думаю что по другому в JS и не получится в общем-то).
Про идею JsonT... Есть данные в виде JSON (подмножество JS литералов), скажем такие вот:
namespace JSONT
{
class DataProxy // data proxy is used as a representation of current data node in rules
{
property undefined( name, v ) // 'undefined' property handler, just return the name as it is
{ get return name; }
}
function transform(data, frules, stream = null)
{
function params2array( params.. ) { return params; } // simply returns paramters as an array, passed to frules generator of rulesvar proxy = new DataProxy(); // data proxy object, represents current data node in rules.var rules = frules(params2array,proxy); // generate rulesvar apply; // forward declaration of the function belowvar out = stream || Stream.openString(); // creating output stream as a StringBuilder or using existingfunction processData(data,path) //
{
if( typeof data == #array )
{
path += "[]";
if( var r = rules[path] )
{
for( var ael in data ) apply(ael,r,path); // for each element in the array apply the rule to it.return;
}
}
out << data.toHtmlString(); // the terminal data, just output it.
}
apply = function(data,rule,path) // applies the rule to the data node (that is on the path)
{
for( var rel in rule )
{
if( typeof rel == #string ) out << rel; // string - output itelse if( rel === proxy ) processData(data,path); // the proxy - process data node it is representingelse if(typeof rel == #symbol) // symbol marks property invocation, produced by <DataProxy.property undefined()>
{
var member = data[rel];
if( member !== undefined )
{
var p = path + "." + rel; var r = rules[p];
if( r ) apply( member, r, p ); // if member rule found, apply it to the member dataelse out << member.toHtmlString(); // otherwise output it.
}
}
}
}
// and finally apply root rule to the root data node
apply(data,rules[""] || [proxy],"");
if( stream ) return stream; // if stream was provided - return it.var rv = out.toString(); // otherwise return string from string builder (our in-memory stream).
out.close();
return rv;
}
}
Интересно, а если что-нибудь аналогчное в Python или Perl?
Здравствуйте, c-smile, Вы писали:
CS>Ниже приведена имплементация JsonT (json transformation) в TIScript.
CS>В качестве идеи использовалась http://goessner.net/articles/jsont/ CS>Проблема с имплементацией оного в JavaScript состоит в том что Stefan Goessner использовал eval() и regular expressions. CS>Что в общем-то накладно при массивном использовании. (Я думаю что по другому в JS и не получится в общем-то).
Получится, нужно честный парсер написать или взять готовый на json.org (например http://www.json.org/json_parse.js etc.).
CS>Про идею JsonT... Есть данные в виде JSON (подмножество JS литералов), скажем такие вот:
... CS>Нужен некий набор правил который описывает трансформацию входных данных в их html представление.
Я далек от web-разработки, но мне всегда казалось, что эту задачу чаще всего решают всякими темплейтными движками, например: http://json-template.googlecode.com
CS>В моем случае эти правила выглядят так:
CS>[code] CS>function rules($,d) CS> { CS> return CS> { CS> "" : $(<ul>{d}</ul>), CS> "[]" : $(<li contact-id="{d.id}">{d.name}{d.email}</li>), CS>Несколько cryptic но тем не менее легко читаемо.
В отсутствие алгебраического паттерн-матчинга, мы задаем правила строками. Возникают вопросы:
— Если это ваш язык — почему не добавить в него настоящий паттерн-матчинг?
— Если вас устраивают правила в виде строк — почему не сделать покруче, как OMETA например? Или портировать LPEG(еще лучше http://github.com/mascarenhas/lpeg-list) для TScript?
Здравствуйте, z00n, Вы писали:
Z>Здравствуйте, c-smile, Вы писали:
CS>>Ниже приведена имплементация JsonT (json transformation) в TIScript.
CS>>В качестве идеи использовалась http://goessner.net/articles/jsont/ CS>>Проблема с имплементацией оного в JavaScript состоит в том что Stefan Goessner использовал eval() и regular expressions. CS>>Что в общем-то накладно при массивном использовании. (Я думаю что по другому в JS и не получится в общем-то).
Z>Получится, нужно честный парсер написать или взять готовый на json.org (например http://www.json.org/json_parse.js etc.).
Я не понял смысл этого высказывания. В JS достаточно написать
var data = eval("(" + jsontext + ")");
чтобы получить из JSON строки данные в готовом виде. Ибо JSON это всегда валидный JS литерал.
Только опять же прчем здесь это. Данные уже есть в памяти в готовом виде.
json_parse.js нужен в одном лишь случае — когда есть вероятность что данные придут со стороны (security matters).
CS>>Про идею JsonT... Есть данные в виде JSON (подмножество JS литералов), скажем такие вот: Z>... CS>>Нужен некий набор правил который описывает трансформацию входных данных в их html представление.
Z>Я далек от web-разработки, но мне всегда казалось, что эту задачу чаще всего решают всякими темплейтными движками, например: http://json-template.googlecode.com
В TIScript из коробки есть встроенный template engine — типа PHP:
<% for(var e in collection) { %>
<p><% =e %></p>
<% } %>
Проблема с этим — это должен быть отдельный файл или stream — не всегда удобно. И что самое основное — плохо читаемое.
CS>>В моем случае эти правила выглядят так:
CS>>[code] CS>>function rules($,d) CS>> { CS>> return CS>> { CS>> "" : $(<ul>{d}</ul>), CS>> "[]" : $(<li contact-id="{d.id}">{d.name}{d.email}</li>), CS>>Несколько cryptic но тем не менее легко читаемо.
Z>В отсутствие алгебраического паттерн-матчинга, мы задаем правила строками. Возникают вопросы: Z>- Если это ваш язык — почему не добавить в него настоящий паттерн-матчинг?
С алгебраическим pattern matching проблемы следующие:
1) template имеет свой собственный distinct micro-syntax. Встраивание такого синткаксиса в C style syntax вызывает определенные проблемы.
2) и честно говоря в UI строении я так и не видел удачных примеров использования оного.
3) JS[ON] объекты не есть DOM элементы. Для эффективного matching по path нужно чтобы каждый объект имел ссылку на parent.
(Или я не понимаю как чистый pattern matching реализовать)
Z>- Если вас устраивают правила в виде строк — почему не сделать покруче, как OMETA например? Или портировать LPEG(еще лучше http://github.com/mascarenhas/lpeg-list) для TScript?
Я не понял как соотносится LPEG с данной проблемой.
Это же yet another regular expression engine. И как я вижу для строк.
CS>>Интересно, а если что-нибудь аналогчное в Python или Perl? Z>У http://json-template.googlecode.com есть python версия,PyStringTemplate Z>и.т.д
JsonT используется на клиенте. Как правило для формирвания представления неких данных полученных с пом. AJAX.
Т.е. в рамках одной функции. А json-template это скорее markup со встроенными макрокомандами. Нужно наоборот.
Это ваш язык — добавьте в него XML литералы, как в Scala
Z>>- Если это ваш язык — почему не добавить в него настоящий паттерн-матчинг?
CS>С алгебраическим pattern matching проблемы следующие: CS>1) template имеет свой собственный distinct micro-syntax. Встраивание такого синткаксиса в C style syntax вызывает определенные проблемы.
У Немерле и Scala нет никаких проблем. Нужно добавить переменные внутри литералов и одно-два ключевых слова.
Реальный код на Scala c XML-литералами (нечто подобное Влад встроил в Nemerle):
...
person match {
case Person(id, firstname, lastName, title) =>
<person>
<id>{id}</id>
<firstName>{firstName}</firstName>
<lastName>{lastName}</lastName>
<title>{title}</title>
</person>
}
CS>2) и честно говоря в UI строении я так и не видел удачных примеров использования оного.
Scala Lift.
CS>3) JS[ON] объекты не есть DOM элементы. Для эффективного matching по path нужно чтобы каждый объект имел ссылку на parent. CS>(Или я не понимаю как чистый pattern matching реализовать)
Не нужна ссылка на parent, не нужен DOM.
CS>Я не понял как соотносится LPEG с данной проблемой. CS>Это же yet another regular expression engine. И как я вижу для строк.
У вас _уже_ используются строки. Если у вас _уже_ строки, почему не взять для них что-то покруче и поуниверсальнее. (PEG и OMETA — это не регэкспы: см. http://www.rsdn.ru/forum/philosophy/3862088.1.aspx
CS>JsonT используется на клиенте. Как правило для формирвания представления неких данных полученных с пом. AJAX. CS>Т.е. в рамках одной функции. А json-template это скорее markup со встроенными макрокомандами. Нужно наоборот.
json-template написан на JS — его можно использовать на клиенте.
Здравствуйте, z00n, Вы писали:
Z>У Немерле и Scala нет никаких проблем. Нужно добавить переменные внутри литералов и одно-два ключевых слова.
Z>Псевдокод a-la Scala: Z>
т.е. в моем случае template описывает path — место в иерархии.
В твоем же примере somerecord match описывает один объект, а не его место в дереве.
CS>>2) и честно говоря в UI строении я так и не видел удачных примеров использования оного. Z>Scala Lift.
CS>>3) JS[ON] объекты не есть DOM элементы. Для эффективного matching по path нужно чтобы каждый объект имел ссылку на parent. CS>>(Или я не понимаю как чистый pattern matching реализовать) Z>Не нужна ссылка на parent, не нужен DOM.
Я утверждаю что нужна такая ссылка. Как и весь остальной набор getNextSibling(), getPreviousSibling() и т.д.
Говоряю на основании моего собственного опыта полномасштабной имплементации CSS selectors matching: http://www.terrainformatica.com/htmlayout/selectors.whtm
CS>>Я не понял как соотносится LPEG с данной проблемой. CS>>Это же yet another regular expression engine. И как я вижу для строк. Z>У вас _уже_ используются строки. Если у вас _уже_ строки, почему не взять для них что-то покруче и поуниверсальнее. (PEG и OMETA — это не регэкспы: см. http://www.rsdn.ru/forum/philosophy/3862088.1.aspx
У меня строка вида "[].name" не разбирается и никак не анализируется. Используется сугубо как ключ в hash-map.
Т.е. я не понимаю зачем "покруче и поуниверсальнее" и/или что ты имеешь ввиду?
CS>>JsonT используется на клиенте. Как правило для формирвания представления неких данных полученных с пом. AJAX. CS>>Т.е. в рамках одной функции. А json-template это скорее markup со встроенными макрокомандами. Нужно наоборот. Z>json-template написан на JS — его можно использовать на клиенте.
CS>т.е. в моем случае template описывает path — место в иерархии.
CS>В твоем же примере somerecord match описывает один объект, а не его место в дереве.
Дерево обходится рекурсивно, с PM это очень удобно. Но здесь не дерево, а просто array of records, поэтому простого map достаточно (псевдокод):
// function map(arr,func)
// {
// var ret = [];
// for (var i = 0; i < arr.Length; ++i)
// ret[i] = func(arr[i]);
// return ret;
// }
function deconstructRecord(record) = record match {
case {id:id, name:name, email:email} =>
$(<li contact-id= $(id)>
<span class="name"> $(name) </span>
<a class="email" href=$(email)> $(email) </a>
</li>)
}
var result = $(<ul> contacts.map(deconstructRecord) </ul>)
Z>>Не нужна ссылка на parent, не нужен DOM. CS>Я утверждаю что нужна такая ссылка. Как и весь остальной набор getNextSibling(), getPreviousSibling() и т.д. CS>Говоряю на основании моего собственного опыта полномасштабной имплементации CSS selectors matching: CS>http://www.terrainformatica.com/htmlayout/selectors.whtm
In this article we discuss and compare five different methods of determining the parent of an SXML node. The existence of these methods is a crucial step in a constructive proof that SXML is a complete model of the XML Information set, and SXPath is a complete implementation of the XPath Recommendation. Four of the five techniques of determining the parenthood require no mutations, and can be implemented in a pure and strict functional language. Three of the five techniques rely on annotations attached to SXML nodes. The techniques differ in the nature of the annotations and in the time complexity of attaching and using these annotations.
CS>У меня строка вида "[].name" не разбирается и никак не анализируется. Используется сугубо как ключ в hash-map. CS>Т.е. я не понимаю зачем "покруче и поуниверсальнее" и/или что ты имеешь ввиду?
И что будет если вместо этого написать "{}.name"? В чем ценность того, что строка не анализирутся?
Здравствуйте, z00n, Вы писали:
CS>>В твоем же примере somerecord match описывает один объект, а не его место в дереве.
Z>Дерево обходится рекурсивно, с PM это очень удобно. Но здесь не дерево, а просто array of records, поэтому простого map достаточно (псевдокод): Z>
Z>// function map(arr,func)
Z>// {
Z>// var ret = [];
Z>// for (var i = 0; i < arr.Length; ++i)
Z>// ret[i] = func(arr[i]);
Z>// return ret;
Z>// }
Z>function deconstructRecord(record) = record match {
Z> case {id:id, name:name, email:email} =>
Z> $(<li contact-id= $(id)>
Z> <span class="name"> $(name) </span>
Z> <a class="email" href=$(email)> $(email) </a>
Z> </li>)
Z>}
Z>var result = $(<ul> contacts.map(deconstructRecord) </ul>)
Z>
А зачем все так сложно? Например зачем там pattern matching?
var out = Stream.openString(); // a.k.a. StringBuilder
out.$(<ul>);
for( var v in contacts )
out.$(<li contact-id={v.id} ><span class="name">{v.name}</span>
<a class="email" href="mailto:{v.email}">{v.email}</a></li>);
out.$(</ul>);
self.$(body).append(out.toString());
out.close();
Так народ и делает в настоящее время.
Проблема с этим состоит в том что при изменении структуры данных меняется структура кода.
JsonT позволяет котлеты отделить.
Z>Другой вариант: пользоваться вместо array одновязным списком(cons list), который так любят функциональные программисты
Проблема в такого рода решениях (embedded XML) состоит в том что это только про XML.
В JS и соответственно в TIS наличествует потребность в embedding всяко разных других языков.
Например CSS selectors:
root.$(input[type="text"]);
или SQL:
var name="Вася";
var rs = db.$query(SELECT salary FROM groshi WHERE name='{name}';);
Чтобы не "корячить" грамматику каждый раз я и ввёл механизм stringizer functions. Вельми удобно.
CS>>У меня строка вида "[].name" не разбирается и никак не анализируется. Используется сугубо как ключ в hash-map. CS>>Т.е. я не понимаю зачем "покруче и поуниверсальнее" и/или что ты имеешь ввиду? Z>И что будет если вместо этого написать "{}.name"?
Ничего не будет ибо смысла не имеет. Дело в том что в JS объект есть неупорядоченный набор key/values — типичный hash-map.
Смысла перебирать его элементы для нужд отображения нет. Т.е. только обращение по полю.
Для массивов — да смысл есть.
Z>В чем ценность того, что строка не анализирутся?
Строка используется просто как ключ в hashmap. Т.е. сложность вычисления O(1).
Для юольших наборов важно.
CS>А зачем все так сложно? Например зачем там pattern matching?
Деконструкция одной записи без проверки ошибок — это вырожденный случай, в реальной жизни клауз обычно несколько. PM, помимо прочего, анализирует свою правильность, т.е. достижимость правых частей и полноту.
CS>Вот то как оно работает прямым обходом CS> <a class="email" href="mailto:{v.email}">{v.email}</a></li>);
А как валидность данных проверяется, например, что v.email != undefined ?
CS>Проблема с этим состоит в том что при изменении структуры данных меняется структура кода. CS>JsonT позволяет котлеты отделить.
Это в науке называется "Expression Problem" — PM vs. Visitor (если я правильно понимаю, что вы хотите сказать) — только PM все равно лучше
CS>Проблема в такого рода решениях (embedded XML) состоит в том что это только про XML. CS>В JS и соответственно в TIS наличествует потребность в embedding всяко разных других языков. CS>Например CSS selectors: CS>или SQL:
Ну тут тоже все уже украдено, набор кирпичей для embedded языков вполне устоялся:
— первоклассные функции (в JS уже есть)
— если вам хочется определять свои control-конструкции то:
-- или макросы а-la Lisp
-- или компактная форма записи лямбд (Smalltalk)
-- или ленивость (Haskell)
— возможность определять пользовательские бинарные(лево и правоассоциативные) и унарные операторы
— встроенная в язык поддержка монад (в принципе можно обойтись библиотекой, как C# Linq без from)
— желательно иметь tail calls optimization
Z>>И что будет если вместо этого написать "{}.name"? CS>Ничего не будет ибо смысла не имеет.
А если по ошибке написать?
CS>Дело в том что в JS объект есть неупорядоченный набор key/values — типичный hash-map. CS>Смысла перебирать его элементы для нужд отображения нет. Т.е. только обращение по полю. CS>Для массивов — да смысл есть.
Речь изначально шла о джейсоне в целом, я не понял, что ваш маленький пример и есть use case.
Здравствуйте, z00n, Вы писали:
Z>Здравствуйте, c-smile, Вы писали:
CS>>А зачем все так сложно? Например зачем там pattern matching? Z>Деконструкция одной записи без проверки ошибок — это вырожденный случай, в реальной жизни клауз обычно несколько. PM, помимо прочего, анализирует свою правильность, т.е. достижимость правых частей и полноту.
Все проверки делаются в момент формирования набора данных для отображения. Скажем средствами SQL или list comprehensions.
Там есть гораздо более мощные и эффективные средства для этого.
CS>>Вот то как оно работает прямым обходом CS>> <a class="email" href="mailto:{v.email}">{v.email}</a></li>); Z>А как валидность данных проверяется, например, что v.email != undefined ?
Пока никак. Будем думать. Как бы так нужно
<a class="email" href="mailto:{v.email}">{v.email || "no email given"}</a></li>);
CS>>Проблема с этим состоит в том что при изменении структуры данных меняется структура кода. CS>>JsonT позволяет котлеты отделить. Z>Это в науке называется "Expression Problem" — PM vs. Visitor (если я правильно понимаю, что вы хотите сказать) — только PM все равно лучше
Это "научное" объяснение не сильно лучше моего если честно. Что лучше что хуже — дело вкуса конкретного индивида.
А нагружать язык ненужными (массе) абстракциями... ну как бы "о сколько их упало в эту бездну".
В принципе я знаю как сделать pattern matching но по эффективности это будет не сильно лучше того что есть сейчас.
А web designer en masse это дело только испугает.
CS>>Проблема в такого рода решениях (embedded XML) состоит в том что это только про XML. CS>>В JS и соответственно в TIS наличествует потребность в embedding всяко разных других языков. CS>>Например CSS selectors: CS>>или SQL: Z>Ну тут тоже все уже украдено, набор кирпичей для embedded языков вполне устоялся: Z>- первоклассные функции (в JS уже есть) Z>- если вам хочется определять свои control-конструкции то: Z> -- или макросы а-la Lisp Z> -- или компактная форма записи лямбд (Smalltalk) Z> -- или ленивость (Haskell)
Т.е. нарисовать еще один Nemerle? А смысл?
Z>- возможность определять пользовательские бинарные(лево и правоассоциативные) и унарные операторы
Пока никто не заказывал.
Z>- встроенная в язык поддержка монад (в принципе можно обойтись библиотекой, как C# Linq без from)
Я слабо понимаю смысл Linq если честно. Если работа с DB то SQL имхо как-то роднее проблеме.
Если это выборка данных в памяти то либо list/array comprehensions https://developer.mozilla.org/en/new_in_javascript_1.7
c генераторами.
Еще раз: я не меняю язык. То что есть вполне меня устраивает.
То что я предложил есть способ решения данной проблемы существующими средствами языка. И в этом весь point.
Z>- желательно иметь tail calls optimization
Это да.
Z>>>И что будет если вместо этого написать "{}.name"? CS>>Ничего не будет ибо смысла не имеет. Z>А если по ошибке написать?
Правило не сработает. Ибо алгоритм такие path не формирует вообще.
CS>>Дело в том что в JS объект есть неупорядоченный набор key/values — типичный hash-map. CS>>Смысла перебирать его элементы для нужд отображения нет. Т.е. только обращение по полю. CS>>Для массивов — да смысл есть. Z>Речь изначально шла о джейсоне в целом, я не понял, что ваш маленький пример и есть use case.
Я про джейсон и говорю. В нем тоже порядок неопределен для name/values. См. http://www.json.org/
Массивы — единственные ordered collections.
Здравствуйте, c-smile, Вы писали:
Z>>А как валидность данных проверяется, например, что v.email != undefined ? CS>Пока никак. Будем думать. Как бы так нужно CS><a class="email" href="mailto:{v.email}">{v.email || "no email given"}</a></li>);
Тут все не так просто, например v.v2.email уже так просто не проверишь — нужно убедиться что v2 object.
Для такого вырожденного случая PM === проверка валидности, дальше все естественно сводится к обращению к полям:
-- (примеры на луа, все тоже самое, только '=' вместо ':' для обозначения полей и nil вместо undefined)
fun deconstructRecord
| {id=id, name=name, email=email} -> print(id,name,email)
| _ -> print("fuckup")
end
превращается в:
function deconstructRecord(_u0)
if type(_u0)=='table'and #_u0==0 and _u0.id~=nil and
_u0.name~=nil and _u0.email~=nil
then
return print(_u0.id, _u0.name, _u0.email)
else return print"fuckup"
end
end
... а
fun deconstructNested
| {id=id,{email=email}} -> print(id,email)
| _ -> print("fuckup")
end
превращается в:
function deconstructNested(_u1)
if type(_u1)=='table'and #_u1==1 and
type(_u1[1])=='table'and #_u1[1]==0 and _u1[1].email~=nil and
_u1.id~=nil
then
return print(_u1.id, _u1[1].email)
else return print"fuckup"
end
end
ну и до кучи пример с проверкой достижимости
-- OK - right parts are the same, second clause just redundant
fun deconstrucSomeCorrect
| {a=x,b=y} -> print(x,y)
| {a=x@("A"),b=y} -> print(x,y)
end
-- NOT OK - second clause unreachable
fun deconstrucSomeIncorrect
| {a=x,b=y} -> print(x,y)
| {a=x@("A"),b=y} -> print("With A", x,y)
end
-- There were 1 error(s):
-- pm.hlua:19:5: error: pm: unreachable right-hand side:
-- {a=x@("A"),b=y} -> print("With A", x,y)
CS>Это "научное" объяснение не сильно лучше моего если честно. Что лучше что хуже — дело вкуса конкретного индивида. CS>А нагружать язык ненужными (массе) абстракциями... ну как бы "о сколько их упало в эту бездну". CS>В принципе я знаю как сделать pattern matching но по эффективности это будет не сильно лучше того что есть сейчас. CS>А web designer en masse это дело только испугает.
PM как раз всем очень нравится — поскольку альтернативой обычно является много вложенных if-else
CS>Т.е. нарисовать еще один Nemerle? А смысл?
Я даже не уверен, что макросы лучшее решение — в Haskell, например, DSL получаются даже лучше.
Z>>- встроенная в язык поддержка монад (в принципе можно обойтись библиотекой, как C# Linq без from) CS>Я слабо понимаю смысл Linq если честно. Если работа с DB то SQL имхо как-то роднее проблеме. CS>Если это выборка данных в памяти то либо list/array comprehensions https://developer.mozilla.org/en/new_in_javascript_1.7 CS>c генераторами.
Видели Reactive Extensions for .NET (Rx)? (и RxJS, кстати тоже). Linq(монады) — это самый общий интерфейс ко всему на свете, list comprehension — это частный случай.
CS>Еще раз: я не меняю язык. То что есть вполне меня устраивает. CS>То что я предложил есть способ решения данной проблемы существующими средствами языка. И в этом весь point.
О чем тут спорить?
CS>Я про джейсон и говорю. В нем тоже порядок неопределен для name/values. См. http://www.json.org/ CS>Массивы — единственные ordered collections.
Ну так значит на вход могут проступать прозвольные деревья из массивов и хэш-таблиц. "Правило не сработает" — не облегчает поиск ошибок.
Здравствуйте, c-smile, Вы писали:
CS>Ниже приведена имплементация JsonT (json transformation) в TIScript.
CS>В качестве идеи использовалась http://goessner.net/articles/jsont/ CS>Проблема с имплементацией оного в JavaScript состоит в том что Stefan Goessner использовал eval() и regular expressions. CS>Что в общем-то накладно при массивном использовании. (Я думаю что по другому в JS и не получится в общем-то).
CS>Про идею JsonT... Есть данные в виде JSON (подмножество JS литералов), скажем такие вот:
CS>
Положим, как бы этом могло выглядеть с обычным ПМ:
function genMany(contacts, idx) {
return match(contacts)
on x::xs -> genOne(x) + genMany(xs)
on [] -> ""
}
function genOne(c) {
return match (c)
on (id=id,name=name,email=email) -> "<li contact-id=$id><span class='name'>$name</span>" +
"<a class='email' href='mailto:$email'>$email</a></li>"
on _ -> ""
}
Честно говоря, мне такой вариант кажется более понятным что ли. Он ближе к XSLT. Плюс если реализовать этот механизм, его можно использовать везде, не только в JSONT.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Положим, как бы этом могло выглядеть с обычным ПМ:
ВВ>
ВВ>function genMany(contacts, idx) {
ВВ> return match(contacts)
ВВ> on x::xs -> genOne(x) + genMany(xs)
ВВ> on [] -> ""
ВВ>}
ВВ>function genOne(c) {
ВВ> return match (c)
ВВ> on (id=id,name=name,email=email) -> "<li contact-id=$id><span class='name'>$name</span>" +
ВВ> "<a class='email' href='mailto:$email'>$email</a></li>"
ВВ> on _ -> ""
ВВ>}
ВВ>
ВВ>Честно говоря, мне такой вариант кажется более понятным что ли. Он ближе к XSLT. Плюс если реализовать этот механизм, его можно использовать везде, не только в JSONT.
Я в принипе ни за ни против pattern matching.
Проблема в том что в данной конкретной задаче я использую не patterns самих элементов (т.е. из свойств) а их пути.
Это как бы несколько далеко от того что ты написал. Для того что бы учесть именно пути (т.е. структуру коллекции) тебе
пришлось отходить от чистого PM и вводить как минимум две процедуры. Это уже не декларативность насколько я понимаю.
Про PM собственно: я видел несколько попыток ввести разумную PM нотацию в языки C/C++ syntax группы. Как-то все вельми некузяво смотрится.
То что ты написал выше больше подходит Python/Ruby/Nemerle (в которых \r\n значимый токен а не просто space).
Например это вот в принципе может быть записано как-то так:
function genOne(c)
{
match(c)
{
case {id:any,name:any,email:any} : return $(<li contact-id={c.id}><span class='name'>{c.name}</span>
<a class='email' href='mailto:{c.email}'>{c.email}</a></li>);
default: return "";
}
}
Только в принципе непонятно чем оно реально лучше чем это вот:
CS>Я в принипе ни за ни против pattern matching.
CS>Проблема в том что в данной конкретной задаче я использую не patterns самих элементов (т.е. из свойств) а их пути. CS>Это как бы несколько далеко от того что ты написал. Для того что бы учесть именно пути (т.е. структуру коллекции) тебе CS>пришлось отходить от чистого PM и вводить как минимум две процедуры.
Ну я бы понимал всю эту задачу так — нет никакого JSON или JSONT. Есть литералы объектов в языке. И нужно удобное средство для их анализа. И тут напрашивается два варианта — либо PM в классическом ML-ном виде как "зарекомендовавшее" себя средство, либо XSLT, т.е. XPath. Не свой какой-то странный DSL, который ты изобразил (и который к тому же является просто ключами для некой хэш-таблицы), а именно самый настоящий XPath, возможно, даже реализованный по спецификации, со своим литералом.
Что лучше — вопрос. Классический ПМ предполагает рекурсивный разбор, языку не помешает оптимизация хвостовой рекурсии (хотя ее в принципе несложно добавить). ПМ умеет делать биндинг, XPath — нет.
В любом случае изобретение своего DSL мне кажется неправильным.
Пока мне кажется, что ПМ как возможность может оказаться более универсальной штукой в языке — т.е. стать более ценным добавлением именно в язык — чем поддержка XPath.
CS>Это уже не декларативность насколько я понимаю.
Ну а чем мешают две процедуры? Мне так удобнее. Я сделал функциональную декомпозицию Очень как раз декларативно. Аналогичный код на XSLT вышлядел у меня бы очень похоже. Плюс, если мне придется разбирать объекты (id,name,email) из другого списка — то вот, функция уже готова, никакого copy paste.
CS>Про PM собственно: я видел несколько попыток ввести разумную PM нотацию в языки C/C++ syntax группы. Как-то все вельми некузяво смотрится.
Ну это спорно, честно говоря. Не скрою, что использование оператора | для разделения вхождений матча мне не нравится самому, т.к. такой оператор уже используется и имеет несколько иной смысл в остальных местах. А так, синтаксис матча можно довести до вполне Си-подобного.
Опять же важнее продумать самую возможность, а потом уже решать, как она должна выглядеть. Чисто ML-ный синтаксис матча в Си-подобном Немерле не очень-то людей смущает.
CS>То что ты написал выше больше подходит Python/Ruby/Nemerle (в которых \r\n значимый токен а не просто space).
Если ты про так называемый "двумерный синтаксис", то я, честно говоря, вообще не вижу, как он связан с ПМ. В Немерле — это так, фишка, которой мало кто пользуется. В Скала вообще такого нет. Опять же — где связь? Добавь фигурные скобки вокруг match, а стрелочку замени на двоеточие — получится синтаксис а ля switch/case. Вполне Си-подобный.
CS>Например это вот в принципе может быть записано как-то так: CS>
Хм, честно говоря, твой пример мне непонятен Что он делает-то? Проверяет значения id, name, email с неявным приведением их к bool?
Чтобы я ожидал от своего варианта (применительно к динамическому языку) — проверку, что в переданном объекте действительно присутствуют такие поля как id, email, name. Если проверка неудачно (отсуствуют все или какое-либо поле), то произойдет переход к следующему "кейсу".
Т.е. в данном случае с помощью ПМ мы можем сымитировать структурные типы. У меня, например, есть и такой паттерн без связывания:
if (obj is (:name,:age,:position)) {
}
Или сразу разобрать:
if (obj is (name=n,age=a,position=p)) {
//do something with n, a, p that are scoped to this block
}
В этом как бы фишка ПМ. Высокая концентрация мысли на строчку кода Но конечно не всегда ПМ удобен, иногда удобнее просто if.
CS>Что то в PM наверное есть, но всё как-то реально не доходит до меня. Есть какие-нибудь красивые примеры этого дела?
Красота ПМ — сочетание проверок, иногда довольно сложных, и связывания данных. В функциональных языках ПМ практически везде. Даже присваивание вида let x = 0 есть частный вид ПМа и может выглядеть и как let (x, y) = (0, 1). Наверное, можно попробовать пописать самому, с использованием ПМа, чтобы оценить фишку. Хорошо ИМХО подойдут Скала или Немерле. Объяснить все же сложно.
ВВ>Хм, честно говоря, твой пример мне непонятен Что он делает-то? Проверяет значения id, name, email с неявным приведением их к bool?
Угу.
if с.id,c.name,c.email are all defined and are not empty then ...
ВВ>Чтобы я ожидал от своего варианта (применительно к динамическому языку) — проверку, что в переданном объекте действительно присутствуют такие поля как id, email, name. Если проверка неудачно (отсуствуют все или какое-либо поле), то произойдет переход к следующему "кейсу".
Это оно и есть.
Вот тебе пример в котором вместо '|' используется ':'
Это стандартный HTML/JS т.е. работатет в любом browser.
ВВ>Т.е. в данном случае с помощью ПМ мы можем сымитировать структурные типы. У меня, например, есть и такой паттерн без связывания:
ВВ>
ВВ>if (obj is (:name,:age,:position)) {
ВВ>}
ВВ>
ВВ>В этом как бы фишка ПМ. Высокая концентрация мысли на строчку кода Но конечно не всегда ПМ удобен, иногда удобнее просто if.
Вот тебе более продвинутый пример для Sciter/TIScript. Здесь я определяю новый метод Object.match(patternObject) и использую его как
Как ты видишь это в общем-то достаточно близко к тому что ты нарисовал.
Полный пример для загрузки в Sciter:
<html>
<head>
<style></style>
<script type="text/tiscript">
function Object.match(pattern)
{
for( var (k,v) in pattern )
{
if( v === #exist ) { if( !this.exists(k) ) return false; }
else
{
var thisv = this[k];
if( thisv === undefined ) return false;
else if( v === #non-empty ) { if( !thisv ) return false; }
else if( typeof v == #symbol ){ if( typeof thisv != v ) return false; }
else if( v instanceof RegExp) { if( thisv !like v ) return false; }
else if( v instanceof Type || v instanceof Class) { if( thisv !instanceof v ) return false; }
else if( v != thisv ) { stdout.println(v); return false; }
}
}
return true;
}
function genOne(c)
{
return c.match { id:#exist, name:#exist, email:#exist } ?
"case 1"
: c.match { name:String, email:/[-A-Z0-9._]+@[-A-Z0-9.]+/ } ?
"case 2"
: "none of those";
}
var obj1 = { id:1, name:"A", email:"B" };
var obj2 = { name:"A", email:"AB" };
var obj3 = { name:"A", email:"A@B" };
var obj4 = { name:"A" };
stdout.println( genOne(obj1) );
stdout.println( genOne(obj2) );
stdout.println( genOne(obj3) );
stdout.println( genOne(obj4) );
</script>
</head>
<body>
</body>
</html>
CS>>Что то в PM наверное есть, но всё как-то реально не доходит до меня. Есть какие-нибудь красивые примеры этого дела?
ВВ>Красота ПМ — сочетание проверок, иногда довольно сложных, и связывания данных. В функциональных языках ПМ практически везде. Даже присваивание вида let x = 0 есть частный вид ПМа и может выглядеть и как let (x, y) = (0, 1). Наверное, можно попробовать пописать самому, с использованием ПМа, чтобы оценить фишку. Хорошо ИМХО подойдут Скала или Немерле. Объяснить все же сложно.
Ну как бы в TIScript вот такое
var (x,y) = (0,1);
stdout.println( x, y );
тоже работает только я не понимаю как это соотносится с PM вшитым в язык.
Я действительно хотел бы увидеть пример решения где PM это "самое оно" т.е. без него всё было бы очень плохо.
Про XPath я знаю, это сугубо специфика XML DOM и для JS/Python/Ruby/Perl/etc. мало применимо.
Здравствуйте, c-smile, Вы писали:
CS>Угу. CS>if с.id,c.name,c.email are all defined and are not empty then ... ВВ>>Чтобы я ожидал от своего варианта (применительно к динамическому языку) — проверку, что в переданном объекте действительно присутствуют такие поля как id, email, name. Если проверка неудачно (отсуствуют все или какое-либо поле), то произойдет переход к следующему "кейсу". CS>Это оно и есть.
Я или что-то не понимаю, или это не совсем так. Проверка вида (obj.x) означает, что либо указанного поля в объекте нет вообще, результатом будет "undefined", который неявно приведется к false. Либо поле есть, но у него может быть вполне валидное значение "false". Или же любое другое значение, которое неявно приводится к false.
Честно говоря, такое поведение мне кажется сомнительным.
CS>Вот тебе пример в котором вместо '|' используется ':'
Я имел в виду синтаксис такого плана:
match (x) {
on p1: ...
on p2: ...
default: ...
}
CS>Это стандартный HTML/JS т.е. работатет в любом browser.
Работает, но по-другому
ВВ>>Т.е. в данном случае с помощью ПМ мы можем сымитировать структурные типы. У меня, например, есть и такой паттерн без связывания:
ВВ>>
ВВ>>if (obj is (:name,:age,:position)) {
ВВ>>}
ВВ>>
ВВ>>В этом как бы фишка ПМ. Высокая концентрация мысли на строчку кода Но конечно не всегда ПМ удобен, иногда удобнее просто if.
CS>Вот тебе более продвинутый пример для Sciter/TIScript. Здесь я определяю новый метод Object.match(patternObject) и использую его как CS>
CS>Как ты видишь это в общем-то достаточно близко к тому что ты нарисовал.
Ну в общем, да, это похоже на ПМ. Почему бы это не расширить и привести в более удобную форму?
Как я уже говорил, мне кажется, ты саму задачу формулируешь не совсем верно. Не нужен JSONT. Есть язык, в нем есть объекты, нужно средство для анализа графов. Мне кажется, в таком разрезе предложенный тобой ДСЛ выглядит странно.
CS>>>Что то в PM наверное есть, но всё как-то реально не доходит до меня. Есть какие-нибудь красивые примеры этого дела?
CS>Ну как бы в TIScript вот такое CS>
CS> var (x,y) = (0,1);
CS> stdout.println( x, y );
CS>
CS>тоже работает только я не понимаю как это соотносится с PM вшитым в язык.
Честно, не знаю, как это работает в TIScript, но обычно это и есть ПМ. Просто сокращенный синтаксис. Само собой валидны и:
var (x, 1) = (0, 1);
var (x, (x2, y2)) = ...
var [x, y, 2, (x, y)] = ...
var (name=x, lastName=y) = ...
и пр.
CS>Я действительно хотел бы увидеть пример решения где PM это "самое оно" т.е. без него всё было бы очень плохо.
Такое решение сложно привести, потому что языки, в которых есть ПМ... Ну в них обычно везде ПМ И используется для всего. Идея-то простая, ее можно редуцировать до — вместо того, чтобы сделать проверку и произвести связывание значения, мы пишем одну конструкцию, которая делает и то, и другое. Соответственно, предполагается некий набор встроенных патернов, которые могут разбирать объекты разных типов. Казалось бы самое то для анализа графов.
CS>Про XPath я знаю, это сугубо специфика XML DOM и для JS/Python/Ruby/Perl/etc. мало применимо.
Тут не уверен, что мало применимо. Был, кстати, опыт прикручивания XPath в .NET как для для навигации по графам. Вполне удобно получалось на самом деле. А при желании тот же XPath можно расширить и добавить в него биндинг.
Здравствуйте, Воронков Василий, Вы писали:
CS>>Вот тебе пример в котором вместо '|' используется ':'
ВВ>Я имел в виду синтаксис такого плана:
ВВ>
ВВ>match (x) {
ВВ> on p1: ...
ВВ> on p2: ...
ВВ> default: ...
ВВ>}
ВВ>
CS>>Это стандартный HTML/JS т.е. работатет в любом browser.
ВВ>Работает, но по-другому
Объясни что значит по-другому?
Скажем чем это вот твое:
match (x) {
on p1: ...
on p2: ...
default: ...
}
в принципе отличается от этого:
x like p1? ...
: x like p2? ...
: /*default*/ ...;
}
в Java, C, JavaScript и т.д. (здесь используется каскад <cond>?<then>:<else> операторов если что)
Я имею ввиду результат, а не техническое исполнение и возможные оптимизации.
Что-то мне говорит что результат тот же, нет?
CS>>Вот тебе более продвинутый пример для Sciter/TIScript. Здесь я определяю новый метод Object.match(patternObject) и использую его как CS>>
CS>>Как ты видишь это в общем-то достаточно близко к тому что ты нарисовал.
ВВ>Ну в общем, да, это похоже на ПМ. Почему бы это не расширить и привести в более удобную форму?
Можно подсластить это дело разновидностью switch() оператора, скажем так:
function genOne(c)
{
match(c)
{
case { id:*, name:*, email:* }:
return "case 1";
case { name:String, email:/[-A-Z0-9._]+@[-A-Z0-9.]+/ }:
return "case 2";
default:
return "none of those";
}
}
Так лучше смотрится?
ВВ>Как я уже говорил, мне кажется, ты саму задачу формулируешь не совсем верно. Не нужен JSONT. Есть язык, в нем есть объекты, нужно средство для анализа графов. Мне кажется, в таком разрезе предложенный тобой ДСЛ выглядит странно.
Средство для анализа графов и собственно pattern matching как-то разные вещи, нет?
Проблема в том что XML граф (дерево) образуется одним единственным способом. В универсальном ЯП графы можно строить разными способами.
Например xml node всегда имеет ссылку на parent. В типичных JSON структурах данных (деревьях) такого нет.
Путь в графе образуется только в результате работы некоей функции обхода дерева. Собственно это и есть основное назначение функции JSONT.transform() у меня — перебор элементов графа с генерацией их путей для matching.
CS>>>>Что то в PM наверное есть, но всё как-то реально не доходит до меня. Есть какие-нибудь красивые примеры этого дела?
CS>>Ну как бы в TIScript вот такое CS>>
CS>> var (x,y) = (0,1);
CS>> stdout.println( x, y );
CS>>
CS>>тоже работает только я не понимаю как это соотносится с PM вшитым в язык.
ВВ>Честно, не знаю, как это работает в TIScript, но обычно это и есть ПМ. Просто сокращенный синтаксис. Само собой валидны и:
ВВ>
ВВ>и пр.
CS>>Я действительно хотел бы увидеть пример решения где PM это "самое оно" т.е. без него всё было бы очень плохо.
ВВ>Такое решение сложно привести, потому что языки, в которых есть ПМ... Ну в них обычно везде ПМ И используется для всего. Идея-то простая, ее можно редуцировать до — вместо того, чтобы сделать проверку и произвести связывание значения, мы пишем одну конструкцию, которая делает и то, и другое. Соответственно, предполагается некий набор встроенных патернов, которые могут разбирать объекты разных типов. Казалось бы самое то для анализа графов.
CS>>Про XPath я знаю, это сугубо специфика XML DOM и для JS/Python/Ruby/Perl/etc. мало применимо.
ВВ>Тут не уверен, что мало применимо. Был, кстати, опыт прикручивания XPath в .NET как для для навигации по графам. Вполне удобно получалось на самом деле. А при желании тот же XPath можно расширить и добавить в него биндинг.
Здравствуйте, c-smile, Вы писали:
CS>Объясни что значит по-другому?
Я же вроде написал выше. Твой вариант не проверяет наличие поле, а проверяет его значение. Мой — сначала наличие поля (если поля нет — переходим к другому кейсу), а потом уже значение.
CS>Скажем чем это вот твое: CS>в принципе отличается от этого: CS>в Java, C, JavaScript и т.д. (здесь используется каскад <cond>?<then>:<else> операторов если что)
Синтаксически — ничем. Я и хотел показать, что синтаксис матча можно довести до вполне си-подобного.
CS>Я имею ввиду результат, а не техническое исполнение и возможные оптимизации. CS>Что-то мне говорит что результат тот же, нет?
Что-то мне говорит, что нет.
var obj = { x:0, y:0, z:0 };
function testTernary(obj) {
return obj.x && obj.y && obj.z ? x + ";" + y + ";" + z : "nope";
}
function testPM(obj) {
return match(obj) {
on (x=x,y=y,z=z): x + ";" + y + ";" + z
on _: "nope";
}
}
Результат testTernary: "nope"
Результат testPM: "0;0;0"
Вроде как разный результат?
ВВ>>Как я уже говорил, мне кажется, ты саму задачу формулируешь не совсем верно. Не нужен JSONT. Есть язык, в нем есть объекты, нужно средство для анализа графов. Мне кажется, в таком разрезе предложенный тобой ДСЛ выглядит странно. CS>Средство для анализа графов и собственно pattern matching как-то разные вещи, нет?
ПМ средство, которое можно использовать для анализа графов. Почему бы и нет? Ты ищещь какое-то совсем специализированное средство здесь? Оно в реальности может оказаться хуже, чем тот же ПМ. Например, менее понятным.
CS>Проблема в том что XML граф (дерево) образуется одним единственным способом. В универсальном ЯП графы можно строить разными способами. CS>Например xml node всегда имеет ссылку на parent. В типичных JSON структурах данных (деревьях) такого нет.
Я не очень понимаю, что значит — "xml node всегда имеет ссылку на parent"? Открыл ХМЛ, смотрю, где у него эта ссылка?
А, стоп, ты же не про *литерал* ХМЛ-я, а про объектную модель, в которой ввиду особенностей построения этой объектной модели, есть ссылка на parent.
У меня вот в .NET для самых обычных дотнетных классов были ссылки на parent. А откуда они взялись? Так я их сам и добавлял Потому что, естественно, XPath выполнялся по промежуточному представлению графа. Т.е. получается цепочка (в твоем случае) — JSON -> Дерево для интерпретатора запросов -> по этому дереву уже исполняются запросы. А по-другому с XPath никак. Но я тут большой проблемы не вижу в принципе.
Для ПМ-а — там, да. Промежуточных представлений не надо строить.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Здравствуйте, c-smile, Вы писали:
ВВ>Результат testTernary: "nope" ВВ>Результат testPM: "0;0;0"
obj.x && obj.y && obj.z — проехали.
Я тебе привел имплементацию такого варианта:
obj.match {x:#exist, y:#exist, z:#exist }
здесь проверяется наличие атрибута. Какого бы значения они не были.
ВВ>ПМ средство, которое можно использовать для анализа графов. Почему бы и нет? Ты ищещь какое-то совсем специализированное средство здесь? Оно в реальности может оказаться хуже, чем тот же ПМ. Например, менее понятным.
Ну опять за рибу гроши... Я же тебя и спрашиваю как конкретно можно использовать для анализа графов?
Тебе дадена generic JSON конструкция arrays, maps и терминалы. Нет там никакого DOM.
CS>>Проблема в том что XML граф (дерево) образуется одним единственным способом. В универсальном ЯП графы можно строить разными способами. CS>>Например xml node всегда имеет ссылку на parent. В типичных JSON структурах данных (деревьях) такого нет.
ВВ>Я не очень понимаю, что значит — "xml node всегда имеет ссылку на parent"? Открыл ХМЛ, смотрю, где у него эта ссылка? ВВ>А, стоп, ты же не про *литерал* ХМЛ-я, а про объектную модель, в которой ввиду особенностей построения этой объектной модели, есть ссылка на parent.
ВВ>У меня вот в .NET для самых обычных дотнетных классов были ссылки на parent. А откуда они взялись? Так я их сам и добавлял Потому что, естественно, XPath выполнялся по промежуточному представлению графа. Т.е. получается цепочка (в твоем случае) — JSON -> Дерево для интерпретатора запросов -> по этому дереву уже исполняются запросы. А по-другому с XPath никак. Но я тут большой проблемы не вижу в принципе.
Представь себе дерево в котором кроме всего прочего лежат ссылки на элементы DOM какого-нибудь. Со своими собственными parent и пр. которые не имееют ничего общего с parent в этом самом дереве.
Единственный способ определить пути в таких деревьях это строить их динамически в момент обхода. Собственно способ обхода и опреределят структуру дерева.
Короче: на DOM деревьях у элементов parent наличествует в единственном экземпляре. Но объекты в памяти могут участвовать в нескольких коллекциях одновременно — т.е. иметь несколько parents.
Я тебя спрашиваю: как с помощью ПМ построить универсальный механизм разбора деревьев если у элемента могут быть неизвестное число parents?
При чем здесь PM вообще?
Разве что RE на path образюущихся в результате конкретного способа обхода. Что я конкретно и сделал. Но ты говоришь что можно лучше. Как? Скажешь ты в конце концов?
Здравствуйте, c-smile, Вы писали:
CS>Я тебе привел имплементацию такого варианта: CS>obj.match {x:#exist, y:#exist, z:#exist } CS>здесь проверяется наличие атрибута. Какого бы значения они не были.
Ну к этому претензий нет. Ты приводишь конструкции, аналогичные по семантике ПМ-у и спрашиваешь, зачем нужен ПМ.
ВВ>>ПМ средство, которое можно использовать для анализа графов. Почему бы и нет? Ты ищещь какое-то совсем специализированное средство здесь? Оно в реальности может оказаться хуже, чем тот же ПМ. Например, менее понятным. CS>Ну опять за рибу гроши... Я же тебя и спрашиваю как конкретно можно использовать для анализа графов? CS>Тебе дадена generic JSON конструкция arrays, maps и терминалы. Нет там никакого DOM.
CS>>>Проблема в том что XML граф (дерево) образуется одним единственным способом. В универсальном ЯП графы можно строить разными способами. CS>>>Например xml node всегда имеет ссылку на parent. В типичных JSON структурах данных (деревьях) такого нет.
ВВ>>У меня вот в .NET для самых обычных дотнетных классов были ссылки на parent. А откуда они взялись? Так я их сам и добавлял Потому что, естественно, XPath выполнялся по промежуточному представлению графа. Т.е. получается цепочка (в твоем случае) — JSON -> Дерево для интерпретатора запросов -> по этому дереву уже исполняются запросы. А по-другому с XPath никак. Но я тут большой проблемы не вижу в принципе. CS>Представь себе дерево в котором кроме всего прочего лежат ссылки на элементы DOM какого-нибудь. Со своими собственными parent и пр. которые не имееют ничего общего с parent в этом самом дереве. CS>Единственный способ определить пути в таких деревьях это строить их динамически в момент обхода. Собственно способ обхода и опреределят структуру дерева.
Ну да. В принципе любое дерево преобразовать в XPath DOM
CS>Короче: на DOM деревьях у элементов parent наличествует в единственном экземпляре. Но объекты в памяти могут участвовать в нескольких коллекциях одновременно — т.е. иметь несколько parents.
Я не очень понимаю, в чем проблема. Наличие нескольких parents не мешают построить XPath DOM.
CS>Я тебя спрашиваю: как с помощью ПМ построить универсальный механизм разбора деревьев если у элемента могут быть неизвестное число parents? CS>При чем здесь PM вообще?
С помощью ПМ не нужно строить никакого механизма разбора. ПМ это уже универсальный механизм, который может использоваться для разбора. Точно так же условные операторы и циклы for. Просто код с его использованием получается короче и нагляднее, чем императивный. Но это код того же плана, т.е. это не какое-то специальное средство для разбора деревьев, это просто универсальные конструкции языка.
Но дело в том, что эти конструкции языка очень активно используются в ФЯ для анализа графов. Во всяких компиляторах и пр. И они не просто используются, а считаются очень удобными, выдаются за этакое преимущество ФЯ при написании программ такого рода. А компилятор это в первую очередь этакий анализатор разветвленного графа.
Т.е. у меня есть большое сомнение, что здесь можно придумать что-то кардинально лучше, чем ПМ. В противном случае давно бы придумали. А задача проанализировать JSON никакой вроде как особой спецификой не обладает.
CS>Разве что RE на path образюущихся в результате конкретного способа обхода. Что я конкретно и сделал. Но ты говоришь что можно лучше. Как? Скажешь ты в конце концов?
Я считаю, что даже через XPath лучше. Ты в реальности и изобрел "этакий XPath" на свой манер, причем, если апеллировать к твоему же аргументу про то, что будет привычно/непривычно веб-разработчикам, то XPath-то уже они точно должны знать.
Ты говорил, что у тебя вхождения являются ключами в некой хэш-таблице, но для этого тебе придется раскручивать весь граф, вычисляя все возможные пути? Т.е. ты фактически изначально строишь все возможные запросы, которые можно сделать? Я правильно понимаю?
Так вот — XPath будет лучше и серьезно лучше.
Он также предполагает необходимость предварительного анализа JSON и построения XPath DOM. Но это именно DOM, а не перебор всех вариантов запросов. К тому же он должен строиться лениво — пока ты не дойдешь до детей какого-то конкретного элемента, DOM для них не построится.
XPath DOM по факту пишется для чего угодно. Есть сомнения в этом — возьми .NET, погугли на XPathNavigator. В .NET собственный навигатор создается легко и просто. Кстати, недолго сделать его и для JSON.
Наконец XPath — это привычная людям штука, с привычным синтаксисом.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Ну да. В принципе любое дерево преобразовать в XPath DOM
XPath DOM есть XML DOM как я понимаю.
ВВ>Так вот — XPath будет лучше и серьезно лучше.
Преобразование JSON в XML DOM это потеря иноформации.
JSON (как структура данных) имеет два типа коллекций: arrays и maps. Терминалы тоже типизированы — strings, boolean, numeric.
XML DOM имеет только списки и unisex nodes.
Представление JSON предельно компактно в памяти:
Скажем массив [1,2,3] это примерно 20 байт (5*sizeof(int)). В XML каждая node это как минимум 20 байт, так nodes здесь нужно 4.
Т.е. для данного случая имеем N*N требование по памяти вместо N.
Ты предлагаешь забавный и предельно дорогой способ удалять зубы.
ВВ>Наконец XPath — это привычная людям штука, с привычным синтаксисом.
В JS/Ruby/Python use cases? Сомневаюсь.
Во всяком случае никто в здравом уме не занимается предобразованием, скажем в Python, структур данных в XPath
чтобы сделать запрос на коллекцию. Чтобы потом получить из найденного DOM элемента восставновить искомый объект.
Короче все что угодно, например тот же LINQ, но только не преобразование данных ЯП->XML->ЯП.
Я знаю компании где за такие "решения" с работы выгоняют.