TIScript, JsonT implementation.
От: c-smile Канада http://terrainformatica.com
Дата: 05.08.10 20:57
Оценка: 2 (1)
Ниже приведена имплементация JsonT (json transformation) в TIScript.

В качестве идеи использовалась http://goessner.net/articles/jsont/
Проблема с имплементацией оного в JavaScript состоит в том что Stefan Goessner использовал eval() и regular expressions.
Что в общем-то накладно при массивном использовании. (Я думаю что по другому в JS и не получится в общем-то).

Про идею JsonT... Есть данные в виде JSON (подмножество JS литералов), скажем такие вот:

 var contacts = [
      { id: "1", name:"John", email:"john@example.com" },
      { id: "2", name:"Steve", email:"steve@example.com" },
      { id: "3", name:"Masha", email:"masha@example.com" },
      { id: "4", name:"Alpha", email:"alpha@example.com" },
      { id: "5", name:"Beta", email:"beta@example.com" },
      { id: "6", name:"Gamma", email:"gamma@example.com" }
    ];


Допустим нужно по этим данным сгенерировать следующий HTML:
<ul>
   <li contact-id="1"><span class="name">John</span>
                      <a class="email" href="mailto:john@example.com">john@example.com</a></li>
   <li contact-id="2"><span class="name">Steve</span>
                      <a class="email" href="mailto:steve@example.com">steve@example.com</a></li>
   ...
</ul>


Нужен некий набор правил который описывает трансформацию входных данных в их html представление.

В моем случае эти правила выглядят так:

function rules($,d)
    {
      return 
      { 
        ""         : $(<ul>{d}</ul>),
        "[]"       : $(<li contact-id="{d.id}">{d.name}{d.email}</li>),
        "[].name"  : $(<span class="name">{d}</span>),
        "[].email" : $(<a class="email" href="mailto:{d}">{d}</a>)
      };
    }

т.е. некая custom функция возврщающая map of pairs : data-node-path -> rule.
Несколько cryptic но тем не менее легко читаемо. ( Особенно в ScIDE )

Имплементация JSONT.transform() приведена ниже, а вот test.htm файл если кто-то захочет попробовать (в Sciter):

<head>
  <style>
  
    span.name { display:inline-block; width:8em; }
  
  </style>  
  <script type="text/tiscript">
    include "jsont.tis";
    
    var contacts = [
      { id: "1", name:"John", email:"john@example.com" },
      { id: "2", name:"Steve", email:"steve@example.com" },
      { id: "3", name:"Masha", email:"masha@example.com" },
      { id: "4", name:"Alpha", email:"alpha@example.com" },
      { id: "5", name:"Beta", email:"beta@example.com" },
      { id: "6", name:"Gamma", email:"gamma@example.com" }
    ];
    
    function rules($,d)
    {
      return 
      { 
        ""         : $(<ul>{d}</ul>),
        "[]"       : $(<li contact-id="{d.id}">{d.name}{d.email}</li>),
        "[].name"  : $(<span class="name">{d}</span>),
        "[].email" : $(<a class="email" href="mailto:{d}">{d}</a>)
      };
    }   

    var r = JSONT.transform(contacts,rules);  
    stdout.println(r);
    self.$(body).append(r);
    
  </script>  
</head>
<body>
</body>


Имплементация, jsont.tis :

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 rules
    var proxy = new DataProxy();                          // data proxy object, represents current data node in rules.
    var rules = frules(params2array,proxy);               // generate rules
    
    var apply; // forward declaration of the function below
    var out = stream || Stream.openString();              // creating output stream as a StringBuilder or using existing
    
    function 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 it
        else if( rel === proxy ) processData(data,path);  // the proxy - process data node it is representing
        else 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 data
            else 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?
Re: TIScript, JsonT implementation.
От: z00n  
Дата: 06.08.10 04:43
Оценка:
Здравствуйте, 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?



CS>Интересно, а если что-нибудь аналогчное в Python или Perl?

У http://json-template.googlecode.com есть python версия,PyStringTemplate
и.т.д
Re[2]: TIScript, JsonT implementation.
От: c-smile Канада http://terrainformatica.com
Дата: 06.08.10 05:29
Оценка:
Здравствуйте, 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>и.т.д

Это http://json-template.googlecode.com/svn/trunk/doc/Introducing-JSON-Template.html если честно не сильно отличается от PHP.
Как я уже сказал это не всегда удобно в случае встренного скрипта.

JsonT используется на клиенте. Как правило для формирвания представления неких данных полученных с пом. AJAX.
Т.е. в рамках одной функции. А json-template это скорее markup со встроенными макрокомандами. Нужно наоборот.
Re[3]: TIScript, JsonT implementation.
От: z00n  
Дата: 06.08.10 07:43
Оценка:
Это ваш язык — добавьте в него XML литералы, как в Scala

Z>>- Если это ваш язык — почему не добавить в него настоящий паттерн-матчинг?


CS>С алгебраическим pattern matching проблемы следующие:

CS>1) template имеет свой собственный distinct micro-syntax. Встраивание такого синткаксиса в C style syntax вызывает определенные проблемы.
У Немерле и Scala нет никаких проблем. Нужно добавить переменные внутри литералов и одно-два ключевых слова.

Псевдокод a-la Scala:
...
somerecord 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>)
}


Реальный код на 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
Автор: VladD2
Дата: 30.06.10
)


CS>JsonT используется на клиенте. Как правило для формирвания представления неких данных полученных с пом. AJAX.

CS>Т.е. в рамках одной функции. А json-template это скорее markup со встроенными макрокомандами. Нужно наоборот.
json-template написан на JS — его можно использовать на клиенте.
Re[4]: TIScript, JsonT implementation.
От: c-smile Канада http://terrainformatica.com
Дата: 06.08.10 16:21
Оценка:
Здравствуйте, z00n, Вы писали:

Z>У Немерле и Scala нет никаких проблем. Нужно добавить переменные внутри литералов и одно-два ключевых слова.


Z>Псевдокод a-la Scala:

Z>
Z>...
Z>somerecord 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>


Как этот case будет выглядеть в случае этого вот template? :

".contacts[].email"

Данные:
{
   contacts: [
      { id:1, email:"a@b.c" } //<< matches 'email' here 
      ...
   ]
}

т.е. в моем случае 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
Автор: VladD2
Дата: 30.06.10
)


У меня строка вида "[].name" не разбирается и никак не анализируется. Используется сугубо как ключ в hash-map.
Т.е. я не понимаю зачем "покруче и поуниверсальнее" и/или что ты имеешь ввиду?

CS>>JsonT используется на клиенте. Как правило для формирвания представления неких данных полученных с пом. AJAX.

CS>>Т.е. в рамках одной функции. А json-template это скорее markup со встроенными макрокомандами. Нужно наоборот.
Z>json-template написан на JS — его можно использовать на клиенте.

Можно но в этом виде он там никому не нужен.
Посмотри на количество звезд здесь: http://plugins.jquery.com/project/jsont
Re[5]: TIScript, JsonT implementation.
От: z00n  
Дата: 06.08.10 20:07
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Как этот case будет выглядеть в случае этого вот template? :


CS>
CS>".contacts[].email" 
CS>

CS>Данные:
CS>
CS>{
CS>   contacts: [
CS>      { id:1, email:"a@b.c" } //<< matches 'email' here 
CS>      ...
CS>   ]
CS>}
CS>

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>)


Другой вариант: пользоваться вместо array одновязным списком(cons list), который так любят функциональные программисты
Автор: z00n
Дата: 24.04.08
.
Можно еще как в Scala добавить к PM XPath.


Z>>Не нужна ссылка на parent, не нужен DOM.

CS>Я утверждаю что нужна такая ссылка. Как и весь остальной набор getNextSibling(), getPreviousSibling() и т.д.
CS>Говоряю на основании моего собственного опыта полномасштабной имплементации CSS selectors matching:
CS>http://www.terrainformatica.com/htmlayout/selectors.whtm

Олег же все уже украл до нас: http://okmij.org/ftp/Scheme/xml.html#parent-ptr

On parent pointers in SXML trees

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"? В чем ценность того, что строка не анализирутся?
Re[6]: TIScript, JsonT implementation.
От: c-smile Канада http://terrainformatica.com
Дата: 07.08.10 00:26
Оценка:
Здравствуйте, 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?

Вот то как оно работает прямым обходом ( $name() это "stringizer" функция ):

    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), который так любят функциональные программисты
Автор: z00n
Дата: 24.04.08
.

Z>Можно еще как в Scala добавить к PM XPath.

О, а это еще зачем?
В JS он кстати тоже есть https://developer.mozilla.org/En/E4X/Processing_XML_with_E4X но не нашел понимания в community.

Проблема в такого рода решениях (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).
Для юольших наборов важно.
Re[7]: TIScript, JsonT implementation.
От: z00n  
Дата: 07.08.10 05:20
Оценка:
Здравствуйте, c-smile, Вы писали:


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.
Re[8]: TIScript, JsonT implementation.
От: c-smile Канада http://terrainformatica.com
Дата: 07.08.10 06:37
Оценка:
Здравствуйте, 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.
Re[9]: TIScript, JsonT implementation.
От: z00n  
Дата: 07.08.10 08:52
Оценка:
Здравствуйте, 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.
Ну так значит на вход могут проступать прозвольные деревья из массивов и хэш-таблиц. "Правило не сработает" — не облегчает поиск ошибок.
Re: TIScript, JsonT implementation.
От: Воронков Василий Россия  
Дата: 12.10.10 07:21
Оценка:
Здравствуйте, 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>
CS> var contacts = [
CS>      { id: "1", name:"John", email:"john@example.com" },
CS>      { id: "2", name:"Steve", email:"steve@example.com" },
CS>      { id: "3", name:"Masha", email:"masha@example.com" },
CS>      { id: "4", name:"Alpha", email:"alpha@example.com" },
CS>      { id: "5", name:"Beta", email:"beta@example.com" },
CS>      { id: "6", name:"Gamma", email:"gamma@example.com" }
CS>    ];
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.
Re[2]: TIScript, JsonT implementation.
От: c-smile Канада http://terrainformatica.com
Дата: 12.10.10 22:13
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Положим, как бы этом могло выглядеть с обычным ПМ:


ВВ>
ВВ>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 "";
  }
}


Только в принципе непонятно чем оно реально лучше чем это вот:
function genOne(c) 
{
  return (c.id && c.name && c.email)?
    $(<li contact-id={c.id}><span class='name'>{c.name}</span>
      <a class='email' href='mailto:{c.email}'>{c.email}</a></li>)
    :"";
}


Что то в PM наверное есть, но всё как-то реально не доходит до меня. Есть какие-нибудь красивые примеры этого дела?
Re[3]: TIScript, JsonT implementation.
От: Воронков Василий Россия  
Дата: 13.10.10 06:49
Оценка:
Здравствуйте, c-smile, Вы писали:


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>
CS>function genOne(c) 
CS>{
CS>  match(c) 
CS>  {
CS>     case {id:any,name:any,email:any} : return $(<li contact-id={c.id}><span class='name'>{c.name}</span>
CS>                                            <a class='email' href='mailto:{c.email}'>{c.email}</a></li>);
CS>     default: return "";
CS>  }
CS>}
CS>


CS>Только в принципе непонятно чем оно реально лучше чем это вот:

CS>
CS>function genOne(c) 
CS>{
CS>  return (c.id && c.name && c.email)?
CS>    $(<li contact-id={c.id}><span class='name'>{c.name}</span>
CS>      <a class='email' href='mailto:{c.email}'>{c.email}</a></li>)
CS>    :"";
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). Наверное, можно попробовать пописать самому, с использованием ПМа, чтобы оценить фишку. Хорошо ИМХО подойдут Скала или Немерле. Объяснить все же сложно.
Re[4]: TIScript, JsonT implementation.
От: c-smile Канада http://terrainformatica.com
Дата: 13.10.10 19:45
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

CS>>Например это вот в принципе может быть записано как-то так:

CS>>
CS>>function genOne(c) 
CS>>{
CS>>  match(c) 
CS>>  {
CS>>     case {id:any,name:any,email:any} : return $(<li contact-id={c.id}><span class='name'>{c.name}</span>
CS>>                                            <a class='email' href='mailto:{c.email}'>{c.email}</a></li>);
CS>>     default: return "";
CS>>  }
CS>>}
CS>>


CS>>Только в принципе непонятно чем оно реально лучше чем это вот:

CS>>
CS>>function genOne(c) 
CS>>{
CS>>  return (c.id && c.name && c.email)?
CS>>    $(<li contact-id={c.id}><span class='name'>{c.name}</span>
CS>>      <a class='email' href='mailto:{c.email}'>{c.email}</a></li>)
CS>>    :"";
CS>>}
CS>>


ВВ>Хм, честно говоря, твой пример мне непонятен Что он делает-то? Проверяет значения id, name, email с неявным приведением их к bool?


Угу.
if с.id,c.name,c.email are all defined and are not empty then ...

ВВ>Чтобы я ожидал от своего варианта (применительно к динамическому языку) — проверку, что в переданном объекте действительно присутствуют такие поля как id, email, name. Если проверка неудачно (отсуствуют все или какое-либо поле), то произойдет переход к следующему "кейсу".


Это оно и есть.


Вот тебе пример в котором вместо '|' используется ':'

<html>
<head>
  <style></style>  
  <script type="text/javascript">

  function genOne(c) 
  {
    return c.id && c.name && c.email ? "case 1"
           : c.name && c.email ? "case 2" 
           : "none of those"; 
  }
  
  var obj1 = { id:1, name:"A", email:"B" };
  var obj2 = { name:"A", email:"B" };
  var obj3 = { name:"A" };
  
  alert( genOne(obj1) );
  alert( genOne(obj2) );
  alert( genOne(obj3) );
 
  </script>  
</head>
<body>
</body>
</html>


Это стандартный HTML/JS т.е. работатет в любом browser.

ВВ>Т.е. в данном случае с помощью ПМ мы можем сымитировать структурные типы. У меня, например, есть и такой паттерн без связывания:


ВВ>
ВВ>if (obj is (:name,:age,:position)) {

ВВ>}
ВВ>


ВВ>В этом как бы фишка ПМ. Высокая концентрация мысли на строчку кода Но конечно не всегда ПМ удобен, иногда удобнее просто if.


Вот тебе более продвинутый пример для Sciter/TIScript. Здесь я определяю новый метод Object.match(patternObject) и использую его как

  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"; 
  }


Как ты видишь это в общем-то достаточно близко к тому что ты нарисовал.


Полный пример для загрузки в 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. мало применимо.
Re[5]: TIScript, JsonT implementation.
От: Воронков Василий Россия  
Дата: 15.10.10 09:52
Оценка:
Здравствуйте, 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>  function genOne(c) 
CS>  {
CS>    return  c.match{ id:#exist, name:#exist, email:#exist } ? 
CS>              "case 1"
CS>            : c.match{ name:String, email:/[-A-Z0-9._]+@[-A-Z0-9.]+/ } ? 
CS>              "case 2" 
CS>            : "none of those"; 
CS>  }
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 можно расширить и добавить в него биндинг.
Re[6]: TIScript, JsonT implementation.
От: c-smile Канада http://terrainformatica.com
Дата: 15.10.10 18:44
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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>>  function genOne(c) 
CS>>  {
CS>>    return  c.match{ id:#exist, name:#exist, email:#exist } ? 
CS>>              "case 1"
CS>>            : c.match{ name:String, email:/[-A-Z0-9._]+@[-A-Z0-9.]+/ } ? 
CS>>              "case 2" 
CS>>            : "none of those"; 
CS>>  }
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, но обычно это и есть ПМ. Просто сокращенный синтаксис. Само собой валидны и:


ВВ>
ВВ>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 можно расширить и добавить в него биндинг.
Re[7]: TIScript, JsonT implementation.
От: Воронков Василий Россия  
Дата: 15.10.10 19:10
Оценка:
Здравствуйте, 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 никак. Но я тут большой проблемы не вижу в принципе.

Для ПМ-а — там, да. Промежуточных представлений не надо строить.
Re[8]: TIScript, JsonT implementation.
От: c-smile Канада http://terrainformatica.com
Дата: 15.10.10 22:05
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, 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 образюущихся в результате конкретного способа обхода. Что я конкретно и сделал. Но ты говоришь что можно лучше. Как? Скажешь ты в конце концов?
Re[9]: TIScript, JsonT implementation.
От: Воронков Василий Россия  
Дата: 16.10.10 06:21
Оценка:
Здравствуйте, 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 — это привычная людям штука, с привычным синтаксисом.
Re[10]: TIScript, JsonT implementation.
От: c-smile Канада http://terrainformatica.com
Дата: 16.10.10 18:16
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Ну да. В принципе любое дерево преобразовать в 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->ЯП.
Я знаю компании где за такие "решения" с работы выгоняют.
Re[11]: TIScript, JsonT implementation.
От: Воронков Василий Россия  
Дата: 17.10.10 08:00
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Здравствуйте, Воронков Василий, Вы писали:

ВВ>>Ну да. В принципе любое дерево преобразовать в XPath DOM
CS>XPath DOM есть XML DOM как я понимаю.

Это есть любой DOM, который ты реализуешь. Можешь называть его как тебе нравится.

ВВ>>Так вот — XPath будет лучше и серьезно лучше.


CS>Преобразование JSON в XML DOM это потеря иноформации.

CS>JSON (как структура данных) имеет два типа коллекций: arrays и maps. Терминалы тоже типизированы — strings, boolean, numeric.
CS>XML DOM имеет только списки и unisex nodes.

XML DOM тут не причем. Речь идет о создании врапперов для объектов, чтобы по ним можно было исполнять запросы XPath (или чего-то *похожего* на XPath).

CS>Представление JSON предельно компактно в памяти:

CS>Скажем массив [1,2,3] это примерно 20 байт (5*sizeof(int)). В XML каждая node это как минимум 20 байт, так nodes здесь нужно 4.

Правда? 20 байт? А сколько байт уходит на хранение дополнительной информации о типе данных в динамическом-то языке? Смешно блин. Теперь мы начали память экономить.
Тот, кому нужно экономить память не пишет на интерпретируемом языке.

CS>Ты предлагаешь забавный и предельно дорогой способ удалять зубы.


Забавный способ — это пробежаться по всему дереву, вычислить все варианты запросов и добавить их в хэш-таблицу. Почему ты считаешь по-другому я не знаю.
А построение промежуточного представления для исполнения запросов — это как бы нормально. Притом что, повторюсь, это представление должно строиться лениво.

ВВ>>Наконец XPath — это привычная людям штука, с привычным синтаксисом.

CS>В JS/Ruby/Python use cases? Сомневаюсь.

А ты не сомневайся, а погугли на XPath to Objects, к примеру.

CS>Во всяком случае никто в здравом уме не занимается предобразованием, скажем в Python, структур данных в XPath

CS>чтобы сделать запрос на коллекцию. Чтобы потом получить из найденного DOM элемента восставновить искомый объект.
CS>Короче все что угодно, например тот же LINQ, но только не преобразование данных ЯП->XML->ЯП.
CS>Я знаю компании где за такие "решения" с работы выгоняют.

За хэш-таблицы то? Да, я тоже знаю.
Re[9]: TIScript, JsonT implementation.
От: Mamut Швеция http://dmitriid.com
Дата: 18.10.10 07:05
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Здравствуйте, Воронков Василий, Вы писали:


ВВ>>Здравствуйте, c-smile, Вы писали:


ВВ>>Результат testTernary: "nope"

ВВ>>Результат testPM: "0;0;0"

CS>obj.x && obj.y && obj.z — проехали.


CS>Я тебе привел имплементацию такого варианта:

CS>obj.match {x:#exist, y:#exist, z:#exist }
CS>здесь проверяется наличие атрибута. Какого бы значения они не были.

ПМ позволяет пройти глубже, чем только один уровень.

Если у нас есть объект.
var Obj = {val,
  {
     val3,
     val4
  }
}


То ПМ позволит сделать и такое:
match Obj
  on {P1, {P2, _}} ...
  on {любая_другая_структура} ...


где первый кейс проверит структуру объекта, а потом присвоит P1=val и P2=val3


dmitriid.comGitHubLinkedIn
Re[10]: TIScript, JsonT implementation.
От: c-smile Канада http://terrainformatica.com
Дата: 18.10.10 16:38
Оценка: 18 (1)
Здравствуйте, Mamut, Вы писали:

CS>>Я тебе привел имплементацию такого варианта:

CS>>obj.match {x:#exist, y:#exist, z:#exist }
CS>>здесь проверяется наличие атрибута. Какого бы значения они не были.

M>ПМ позволяет пройти глубже, чем только один уровень.


M>Если у нас есть объект.

M>
M>var Obj = {val,
M>  {
M>     val3,
M>     val4
M>  }
M>}
M>


M>То ПМ позволит сделать и такое:

M>
M>match Obj
M>  on {P1, {P2, _}} ...
M>  on {любая_другая_структура} ... 
M>


Это все тот же случай, т.е. не решает проблему.
on {P1, {P2, _}} это тест на структуру самого объекта и его содержимого. Но никак не пути самого объекта
отнсительно root.

На примере CSS селекторов:

То что вы называете PM это простые селекторы: attribute, type, class, id и пр. селекторы.
То что я сделал это type + child combinators селекторы.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.