Язык K: Отображение графического интерфейса из данных

от автора

Я как всегда об APL, а точнее о старой версии языка K, которая содержала в себе GUI, с весьма необычным подходом к нему.

К сожалению новые версии языка K решили сосредоточиться на обработке данных и исключили GUI, так что данный подход остался в истории, однако может быть кто-то подскажет аналогичные современные фреймворки — было бы очень интересно посмотреть.

Начнём. Краткое описание API, которое нам доступно:

`show$`v        show variable v `hide$`v        hide variable v 

Это всё, больше нет ничего. Т.е. основная особенность — что GUI в K это прямое отображение данных в памяти. А теперь как с этим можно удобно работать.

Для начала попробуем самое простое:

C:\>k K 3.1 2004-01-28 Copyright (C) 1993-2004 Kx Systems WIN32 2CPU 4030MB ws-1341.x.com 0 EVAL   a:10 _draw 100    / list   a 20 51 12 34 31 51 29 35 17 89   `show$`a 

На экране появляется таблица со списком

Любое значение редактируемое, меняем 35 на 135 и это изменение сразу меняет значение в списке:

  a 20 51 12 34 31 51 29 135 17 89 

Если меняем значение в списке, то оно тутже обновляется в интерфейсе.

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

  a:(10 10000000) _draw 100   / 10 списков по 10 миллионов каждый   `show$`a 


Никаких проблем — всё быстро отображается, прокручивается и редактируется.

Именуем колонки: логично что имя колонки — это ключ, а список — значение из hashtable:

  t:.((`a;10 _draw 100;);(`b;10 _draw 100))   `show$`t 

Но это всё очень просто, смотрим что есть ещё. аттрибуты и триггеры — по сути это просто ключ-значение в hashtable, привязанном к переменной, в зависимости от того есть такое значение или нет — происходят разные действия:

Самый простой пример: добавление label.

  val:10   val..l:"Input field"   `show$`val 

Следующие аттрибуты влияют на отображение в gui:

 Display attributes (for variables that have class).   x     width           integer(KFONT width)   y     height          integer(KFONT height)   a     arrangement     nest of symbols(class `form)   o     options         list of symbols(class `radio)   l     label           string   kl    click label     string (also klr)    Data-display attributes (for variables that have class `data).   functions (monadic, constant or array)        default    e    editable        0 or 1                   1    f    format          string from data         11$(11.2$)    g    getdata         data from string         0$ etc.    u    update          update[old;new]          :    fg   foreground      integer(rrggbb)          0    bg   background      integer(rrggbb)         -1(808080)    expressions/events (strings)    ins, del, f1 ... f12, ctrl_a ... ctrl_z    k, kr, kk    click, click right, double click(precludes e)     c      class(display)  symbol         `data(default) atom, list, dict, list of lists, dict of lists         `chart          as above where atom is list of y values         `plot           as above where atom is matrix of (x;y) values         `check         0 or 1         `radio         symbol (one of ..o; see below)         `button        expression or dictionary of expressions         `form          dictionary of entries of any class(incl. `form) 

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

Для простоты создания словаря — язык позволяет работать в контексте внутри словаря — т.е. аналогия с папками и модулями, которые просто хэш-таблицы:

  \d form   val:100   incr:"val+:1"   incr..l:"Increment"   decr:"val-:1"   decr..l:"Decrement"   incr..c: decr..c: `button   \d ^   form / хэш ключей-значений и хэшей аттрибутов. .((`val;100;)   (`incr    "val+:1"    .((`l;"Increment";)      (`c;`button;)))   (`decr    "val-:1"    .((`l;"Decrement";)      (`c;`button;)))) 

Аттрибутом ..a установим порядок отображения.

  form..a:`incr`val`decr   form.val..e:0    / отключаем редактирование значения. 

..a может быть любой формы. Например добавим пару кнопок.

  form.incr10:"val+:10"   form.decr10:"val+:10"   form.incr10..c : form.decr10..c: `button   form..a:(,`incr;`decr10`val`incr10;,`decr)   form..a (,`incr  `decr10 `val `incr10  ,`decr) 

Т.е. смысл в том, что всё GUI описывается примитивными структурами языка и является их же прямым отображением. Можно включать hash в hash, т.е. включать форму в форму компонуя элементы и тд.

Ну а теперь самое интересное, а именно несколько примеров:

Калькулятор:

calc..a:(`exp    `va`vb`vc`vd    `n0`n1`n2`n3    `n4`n5`n6`n7    `n8`n9`lp`rp    `fa`fs`fm`fd`fe    `eval`clear) / порядок элементов на форме calc:@[_n;1_-1_ calc..a;:[;"exp,:(~_v)`l"]]	/ expressions calc[.;`l]:"abcd0123456789()+-*%:"		/ labels calc.eval:"exp:5:. exp" calc.clear:"exp:\"\"" calc[.;`c]:`button calc.exp:calc.exp..l:""  `show$`calc 

Можно рисовать графики:

  p..c:`chart   p:(5 5) _draw 100   `show$`p 

Или высокохудожественная мазмя:

`show$.,((`p;({[x] (2 30)_draw 30}'!10);.,(`c;`plot;))) 

А теперь удивительная вещь, которая когда-то так удивила своей краткостью и понятностью (при минимальном знании словаря конечно), что я решил начать изучать K глубже:

Broadcast сервер:

d:10 _draw 10  w:!0		/ empty client list  .m.g:{w,:_w;d}	/ return data .m.c:"w@:&~w=_w"	/ retain clients .m.s:{. x;w 3:\:x;}	/ (log `l 5:,x) apply and broadcast  \m i 1     listen on port 1 

Клиент:

h:3:(`;1)	/ connect to server d:h 4:_n	/ get database d..t:"if[0=_w;h 3:(_v;_i;:;_v ._i)]"	/ send my updates  `show$`d 

Вот эти несколько строчек создают сервер с простым списком в качестве данных. А сколько угодно клиентов присоединяются к нему и имеют совместно редактируемый список с обновление в реальном времени, всего 9 строчек. Подобный код (без GUI конечно) в настоящее время используется на многих крупнейших биржах для транспортных и балансировочных узлов, которые обслуживают инстансы баз данных Q (новая версия K).

Картинка конечно не передаёт того как это работает в динамике.

ссылка на оригинал статьи http://habrahabr.ru/post/205844/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *