K (язык программирования)

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 12:05, 2 июня 2016.
К
Парадигма обработчик массивов, функциональный
Спроектировано Arthur Whitney
Разработчики Kx Systems
Первый   появившийся 1993
Печать дисциплины Динамическая строгая
OS Linux, OS X, Windows
Лицензия Платная
Под влиянием
A+, APL, Scheme

K - проприетарный язык обработки массивов, разработанный Артуром Уитни и коммерциализированный Kx Systems. С тех пор была также разработана реализация с открытым исходным кодом - Kona. Язык служит основой для KDB, in-memory колоночной базы данных, и других связанных с ним финансовых продуктов. Язык, разработанный в 1993 году, является вариантом APL и содержит элементы Scheme. Защитники языка подчеркивают его скорость, удобство обработки массивов и выразительный синтаксис.

История

Перед разработкой K, Артур Уитни много работал с APL, сначала в IP Sharp Associates наряду с Кен Айверсон и Роджер Хуэй, а затем в Morgan Stanley при разработке финансовых приложений.

В 1993 году Уитни покинул Morgan Stanley и разработал первую версию K. В то же время он основал Кх Systems, чтобы коммерциализировать продукт и подписал эксклюзивный контракт с Union Bank Швейцарии (UBS). В течение следующих четырех лет он разработал различные финансовые и торговые приложения, используя К для UBS.

Контракт закончился в 1997, когда UBS объединился с швейцарским банком. В 1998 году, Кх Systems выпустили KDB - базу данных, построеную на К. KDB колоночная in-memory база данных, включающая ksql, язык запросов с синтаксисом, похожим на SQL. С тех пор большое число финансовых продуктов были разработаны с использованием К и KDB. kdb/tick и kdb/taq были разработаны в 2001 году, kdb+, 64-разрядная версия kdb, была выпущена в 2003 году и kdb+/tick и kdb+/taq в 2004. kdb+ включена в Q, язык, который объединил функциональность языка K и ksql.

Описание

Один из основных принципов К заключается в том, что он предлагает крайнюю производительность труда программиста за счет своей невероятно большой скорости исполнения и очень небольших исполняемых единиц. Примером этого является, как KDB превосходит Oracle на TPC тестах в скорости выполнения запросов и размере хранения данных, хотя запросы пишутся одним человеком. Кроме того, К-код очень плотный, примерно в 100 раз уменьшенается размера кода при переходе с С на К и почти в 1000 раз при переходе с Java и SQL на К и KSQL.

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

К имеет привязки к другим популярным языкам, таким как C, Java, Visual Basic, и Excel. Также была проделана работа по свыванию с Python и XUL Mozilla. Встроенное межпроцессное взаимодействие и двоичный формат объектов очень просты и документированы, делая другие системы, взаимодействующие с K, такими же простыми.

К является интерпретируемым языком, но исходный код компилируется внутри, но не в абстрактной машине, как в Java или Python. Интерпретатор может быть вызван в интерактивном или не в интерактивном режиме и вы можете скомпилировать исходный файл в бинарный файл для распространения продукции, если захотите.

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

Операторы называются глаголами (verbs), данные называются существительные (nouns). Есть также операторы, которые изменяют другие операторы, их называют наречия (adverbs). Набор некоторых существительных, глаголов и наречий вместе образует блоки или "утверждения". Эти названия были унаследованы от APL и часто заменяются на более банальные - операторы, функции и переменные.

Комментарии и соглашения

Прямой слеш (/) используется для комментариев, когда он стоит в начале строки или имеет место слева от него. К стремится упростить синтасис и победить "сахар". Одна вещь, которая может путать людей - К не имеет правил приоритетов. Все разбирается справа налево. Например, 3 * 2 + 1 в К равно 9, вместо ожидаемых 7. Но вы можете использовать скобки для расстановки приоритетов.

Значения

Есть четыре простых типа значений в К:

  • целое число
  • число с плавающей точкой
  • символ
  • symbol

Есть особый тип NULL (_n) и два составных типа: словари и списки. Составные типы являются контейнерами для других типов. Списки классифицируются как однородные (хранят тип содержащихся в них значений) и разнородные.

Примеры:

  (1; 2.3; 4; 5.6)       / разнородный список с элементами integer и float
  1 2 3 4 5              / однородный список с элементами integer
  1.2 3.4 5.6            / однородный список с элементами float
  "quack"                / однородный список с элементами character
  (1 2; 3.4 5.6; "meow") / список со списками
  (1;2 3;4 5 6)          / вектор с элементами integer

  "abcdefghijlkmnopqrstuvwxyz"[14 8 13 10] / => "oink"

  ("qwerty";"poiuy";"asdf";"jhgfdsa")[;3] / срез проекции => "ruff"

Интерпретатор использует специальные выражения - "символы" - для поиска переменных. Они создаются добавлением ` перед корректным именем переменной:

`myvariable
`"variable_with_..complex_//allowed_name"

Глаголы

Для обеспечения компактности операторы перегружаются дважды и бывают монадические (принимающие один аргумент) и диадические (принимающие два аргумента). В каждом случае оператор имеет различное поведение в зависимости от типа аргументов или домена аргументов.

Примеры:

  !4       / enumerate: список integer от 0 до x-1 => 0 1 2 3

  5!3      / mod: остатки от деления левого на правое => 2

  2!1 2 3  / rotate: циклический сдвиг элементов справа на левый аргумент раз => 3 1 2

  ,2       / enlist: одноэлементный список, содержайщий только 2 => ,2

  1,2      / join: формирует список из левых и правых аргументов => 1 2

  |1 2 3   / reverse: инвертирует список => 3 2 1

  0|1      / max: максимум или логическое OR => 1

  &1 2 3 4 / where: возвращает число указанных элементов => 0 1 1 2 2 2 3 3 3 3

  &0 1 1 0 0 1 / where: индексы единиц => 1 2 5

  0&1      / min: минимум и логическое AND => 0

  4<5      / less-than: предикат - левое меньше чем правое => 1
  <7 4 9   / grade-up: сортирует индескы в порядке возрастания => 1 0 2

  =1 0 1 0 0 3 0 1 3 1  / group: группирует все индексы с одинаковыми значениями
                        / (0 2 7 9
                        /  1 3 4 6
                        /  5 8)

  2=0 1 2 3 4           / equals: сравнивает значения => 0 0 1 0 0

  ?1 0 1 0 0 3 0 1 3 1  / unique: все уникальные элементы в порядке просмотра => 1 0 3

  1 0 1 0 0 3 0 1 3 1?3 / find: первый индекс правого аргумента в левом => 5

Переменные и связи

К динамически строго типизированный язык и переменные не объявляются, но они начинают существовать, когда вы назначаете им значения. Это может быть сделано в любом месте, даже в середине выражения, так как нет никакого различия между утверждениями и выражениями. Если вы попытаетесь прочитать значение из переменной, которая еще не была назначена, это вызовет ошибку. В К также нет указателей. В истинном функциональном стиле, когда вы назначаете переменной значение, происходит глубокое копирование (хотя, К делает это лениво). Назначение осуществляется с помощью двоеточия и читается как "получает" или "есть". Как частный случай, когда присвоение - последнее в выражении, возвращается NULL (это помогает предотвратить захламление отображаемого журнала). Вы можете заставить возвращать значения из оператора присваивания, используя вариант монадического двоеточия.

Примеры:

  a:"moo"       / a получает значение строки "moo"
  b:!10         / b получает enumerate 10 (список integer от 0 до 9)
  :c:b          / c получает значение b, но изменения b не отражаются на c => 0 1 2 3 4 5 6 7 8 9

  :h:(g*2),g:1+2 / h получает g раз 2 * g, где g получает 1 + 2 => 6 3
  g              / => 3

Определяемые пользователем функции

{} используются для создания функций; они являются эквивалентом lambda в Lisp. Часто они используются c присвоением переменной получаемой функции, но не всегда. Чтобы создавать компактный код, если функция требует три или менее аргументов, К позволит Вам использовать неявно х, у, z в качестве аргументов. Если вам нужно больше чем три аргумента, необходимо объявить их все. Все функции возвращают значение последнего выполненного оператора, даже если возвращается null. Для вызова функции вы используете скобки (такие же, как для индексации списка). Если вы не подставляете аргумент при вызове функции, он будет проецироваться.

Примеры:

  pyth:{_sqrt(x*x)+y*y} / два явных аргумента
  pyth[30;40]           / => 50.0

  pyth[3 15;4 20]       / => 5 25.0

  dist:{[x1;y1;x2;y2] _sqrt((x2-x1)^2)+(y2-y1)^2}
  dist[1;1;4;5]         / => 5.0

  :d:dist[1;1]          / проецирует на первые 2 аргумента
                        / {[x1;y1;x2;y2] _sqrt((x2-x1)^2)+(y2-y1)^2}[1;1]

  d[7;9]                / => 10.0

  :e:dist[1;;4]         / проецирует на первый и третий аргументы
                        / {[x1;y1;x2;y2] _sqrt((x2-x1)^2)+(y2-y1)^2}[1;;4]

  e[2;6]                / => 5.0

  inc:1+
  inc 8                 / => 9

Системные функции и переменные

Каждый символ, начинающийся с символа подчеркивания, зарезервирован для любой системной переменной или функции. Системные функции используют инфикс, как и их менее читаемые двоюродные братья, но не могут быть перегружены как монадические и диодические как и пользовательские функций (в следующей версии K это будет изменено, и пользователи смогут определять инфиксные функции и перегружать их "n-адически").

Примеры:

  3_draw 5        / список 3 случайных чисел от 0 до 4 => 2 2 4

  2_draw 0        / список 2 случайных дейтвительных чисел от 0 до 1 => 0.2232866 0.9504653

  4_draw-4        / deal: список 4 неповторяющихся случайных чисел от 0 до 3 => 2 0 1 3

  4 13_draw-52    / deal: колоду карт в четыре строки
                  / (29 27 10 0 23 3 28 5 24 16 40 8 22
                  /  51 20 36 47 18 31 26 11 44 37 38 9 13
                  /  39 42 34 50 21 6 19 46 48 45 14 43 2
                  /  33 49 4 25 41 30 35 7 32 17 1 12 15)

  1 3 4 5 7 9_bin 4 / бинарный поиск по списку с возвратом индекса => 2

  1 3 4 5 7 9_binl 2 4 6 / бинарный поиск по списку чисел => 1 2 4

  16_vs 543212    / vector from scalar: изменяет основание на 16 => 8 4 9 14 12

  5 3 2_vs 21     / изменение базовой переменной => 3 1 1

  5 3 2_sv 3 1 1  / scalar from vector: инверсия => 21

  _host`kuro5hin.org / возвращает ip-адрес в виде числа => -815566008

  256_vs _host`kuro5hin.org / формат для отображения => 207 99 115 72

Наречия

Циклы в К пишутся редко (kbd вообще не содержит циклов), вместо них используются наречия. Наречие модифицирует функцию, возвращая другую функцию, изменяя способ обработки ее аргументов. Вот некоторые из стандартных наречий:

  • Over (/) - изменяет диадическую функцию и применяет функцию вниз по списку, собирая результаты.
  • Convrge (/) изменяет монадическую функцию и будет постоянно применять функцию к предыдущему результату, пока не вернется либо начальное значение, либо результат предыдущего значения.
  • Scan (\) функция будет применяться вниз по списку, собирая все промежуточные результаты (иногда это называют trace(след)).
  • Each (') будет применять функцию вниз по списку той же длины (равной "валентности" функции).
  • Each-right (/:) захватит левый аргумент функции и применит функцию вниз по списку правых аргументов.

Примеры:

  +/1 2 3 4          / plus-over (sum): аналогично 1+2+3+4 => 10

  +\1 2 3 4          / plus-scan: возвращает промежуточные значения +/ => 1 3 6 10

  |/5 3 7 4 2        / max-over: сравнивает все элементы как 5|3|7|4|2 => 7

  ,/(1 2;(3 4;5);6)  / join-over: (1 2),(3 4;5),6 => (1;2;3 4;5;6)

  ,//(1 2;(3 4;5);6) / flatten: => 1 2 3 4 5 6

  3 4_draw'-3 -4     / draw-each: (3_draw-3),(4_draw-4)
                     / (1 2 0
                     /  2 0 1 3)

  2_draw/:10 100     / draw-right-each: (2_draw 10),(2_draw 100)
                     / (7 7
                     /  45 91)

Join-over соединяет без выполнения "спрямления" вложенных списков. Этим занимается flatten. Также вы можете использовать flatten-each (,//') и указать столько символов ', сколько уровней списков, считая сверху, не нужно сглаживать.

Условия

Существуют в языке, но используются редко, чаще всего в :. Похоже на условие cond в Lisp: принимает пару аргументов и опционально последний аргумент. Первый аргумент каждой пары проверяется на истину (0 - ложь, все остальные целые числа истинны; все, что не целое число, ошибка) - если он истина, то возвращается результат оценки второй пары. Если она ложна, то тестируется следующая пара. Если все пары были проверены, то вычисляется последний аргумент и возвращается результат. Если последний аргумент не указан и все условия ложны, то возвращается NULL.

Примеры:

  :[0;"true";"false"]          / => "false"

  s:{:[x>0;"+"; x<0;"-"; "0"]} / возвращает знак x или 0
  s 4                          / => "+"
  s -3                         / => "-3"

Проверка, является ли число простым

Предикат простоты:

  isprime:{&amp;/x!/:2_!x}  / min over x mod right-each 2 drop enumerate x  isprime 14 / => 0

  isprime 7  / => 1

  !14 / list of all integers from 0 to x (exclusive)
  / => 0 1 2 3 4 5 6 7 8 9 10 11 12 13 

  2_!14 / remove the first two elements
  / => 2 3 4 5 6 7 8 9 10 11 12 13

  14!/:2_!14 / residue of x and each of the numers in the list
  / => 0 2 2 4 2 0 6 5 4 3 2 1

  &amp;/14!/:2_!14 / number is prime when the lowest residue is 1 (considered true)
  / => 0

K-дерево

Этот элемент хорошо коррелирует с философией языка K, оставляя вещи простыми и мощными. K-дерево может быть использовано для модульности программ, в качестве механизма скоупинга для графического дизайна и как рудиментная объектная система.

Все переменные существуют где-то в K-дереве. Для ссылки на переменную необходимо отделить имя переменной и имя каждой ветки точкой. Корень дерева является пустым символом. Например, полное имя переменной может выглядет так: .branch.subbranch.variable.

Ветки являются словарями. Если вы создадите словарь с символами sym и bol в переменной .tr.ee, то вы можете получить доступ к .tr.ee.sym и .tr.ee.bol. Наоборот, если создать переменные .dict.ion и .dict.ary то переменная .dict будет корректным словарем. Это делает язык очень рефлективным, поскольку теперь вы можете изменять местоположения переменных, областей, и вручную управлять размерами.

Всякий раз, когда вы находитесь в среде K, вы всегда работает в ветке К-дерева. При запуске интерпретатора К он ставит вас в .k ветку. Вы можете перемещаться по дереву с помощью команды directory (\d). Например \d .tw.ig создаст новую ветку tw, затем создаст подветку ig. Вы можете проверить все переменные в ветке с помощью команды отображения списка переменных (\v). Часто сценарий начнется с команды смены каталога, затем определяются все его переменные в этой и, возмжно, в нескольких других ветках. Это пример эффективного использования K-дерева как модульной системы.

  \d .test          / создать новую переменную в корне
  \d ement          / создать подветку
  \d                / показать текущую директорию => .test.ement

  new:`small        / поместить значения в директорию
  old:`big
  \v                / отобразить содержимое => new old

  \d ^              / вернуться на одну директорию в дереве
  \d                / => .test

  \v                / => ement

  ement             / просмотреть значение ement
                    / .((`new;`small;)
                    /  (`old;`big;))

  .test.ement.new   / полный путь => `small

  ement.old         / частичный путь => `big

  ement`old         / индекс как в массиве => `big

Другие уникальные элементы K

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

В К также есть понятие зависимостей и триггеров. Они используются для эффективного расчета данных по запросам и выполнения callback'ов всякий раз, когда значение изменяется (например, так работает система таймеров в К). К будет отслеживать устаревшие зависимости и выполнять только минимальное необходимое количество работы, необходимой для обновления значений.

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

Межпроцессное взаимодействия в K (IPC) и системы взаимодействия по сети также основаны на обратных вызовах и обработчиках сообщений. В K есть простые примитивы, позволяющие доставлять целые структуры данных, или же вы можете делать это самостоятельно. Цель системы IPC така я же, как и цель остальных частей К - сделать работу быстрой, простой, мощной и очень продуктивной.

В то время, когда языкам программирования не хватает оригинальности и новых идей, К находится в выигрышном положении. Но К это не просто язык для исследований, он не для обыкновенного использования. В то время как сообщество может быть небольшим, некоторые пользователи языка могут быть очень большими. Недавние реализации Island ECN и правительства США подверждают расширение языка. Следующая версия языка исправит многие из дыр и неприятностей и уберет вещи, которые многих отталкивали от изучения К.

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

  cut:{1_'(&amp;x=*x)_ x:" ",x}
  cut "Scoop ate my spaces"
  / ("Scoop"
  / "ate"
  / "my"
  / "spaces")

  fibonacci:{x(|+\)\1 1}
  fibonacci 5
  / (1 1
  /  2 1
  /  3 2
  /  5 3
  /  8 5
  /  13 8)

  first:*:
  euclid:{first(|{y!x}\)\x,y} / Euclid's Algorithm
  euclid[24;40]
  / (24 40
  /  16 24
  /  8 16
  /  0 8)

К в финансовых продуктах

К является основой для семейства финансовых продуктов. KDB является in-memory колоночной базой данных, имеющей большую часть функциональности реляционных СУБД. KDB поддерживает SQL, (SQL-92) и ksql, язык запросов с синтаксисом, аналогичным SQL и предназначеным для запросов, основанных на столбцах и анализе массивов.

KDB доступна для Solaris, Linux, OSX и Windows (32-бит или 64-бит).

Ссылки