Mathematica Нотация и синтаксические моды - PullRequest
6 голосов
/ 26 марта 2011

Я экспериментирую с синтаксическими модами в Mathematica, используя пакет нотаций.

Меня не интересуют математические обозначения для конкретного поля, но модификации и расширения синтаксиса общего назначения, особенно обозначения, которые сокращают многословиеVeryLongFunctionNames Mathematica, очищает громоздкие конструкции или расширяет язык приятным способом.

Пример модификации - определение Fold[f, x] для оценки как Fold[f, First@x, Rest@x]
Это хорошо работает и довольно удобно.

Другим было бы определение *{1,2} для оценки как Sequence @@ {1,2} как вдохновлено Python;это может или не может работать в Mathematica.

Пожалуйста, предоставьте информацию или ссылки на адреса:

  • Пределы обозначений и синтаксического изменения

  • Советы и рекомендации по реализации

  • Существующие пакеты, примеры или эксперименты

  • Почему это хорошая или плохая идея

Ответы [ 3 ]

5 голосов
/ 27 марта 2011

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

Было бы проще, если бы был какой-то хук, подобный $PreRead, который позволял бы пользователю перехватывать входную строку и обрабатывать ее в другую строку, прежде чем она будет передана в анализатор. Это позволило бы написать собственный препроцессор, который работает на строковом уровне - или вы можете назвать его компилятором, если хотите - который будет принимать строку любого синтаксиса, которую вы разрабатываете, и генерировать из нее код Mathematica. Я не знаю о таком крючке (это может быть мое невежество конечно). Не имея этого, можно использовать, например, ячейки в стиле program и, возможно, запрограммировать некоторые кнопки, которые читают строку из этих ячеек и вызывают такой препроцессор, чтобы сгенерировать код Mathematica и вставить его в ячейку рядом с той, где оригинальный код

Такой препроцессорный подход будет работать лучше всего, если вы хотите использовать какой-то простой язык (по крайней мере, с точки зрения его синтаксиса и грамматики), чтобы его можно было легко анализировать и анализировать. Если вам нужен язык Mathematica (с его полным синтаксисом по модулю всего нескольких элементов, которые вы хотите изменить), то при таком подходе вам не повезло в том смысле, что независимо от того, насколько мало и «легковесны» ваши изменения, вы ' Мне нужно полностью перестроить парсер Mathematica, просто чтобы внести эти изменения, если вы хотите, чтобы они работали надежно. Другими словами, я говорю о том, что IMO намного проще написать препроцессор, который генерировал бы код Mathematica из какого-то Lisp-подобного языка с небольшим или отсутствующим синтаксисом, чем пытаться реализовать несколько синтаксических модификаций для стандартного mma.

Технически, одним из способов написания такого препроцессора является использование стандартных инструментов, таких как Lex (Flex) и Yacc (Bison), для определения вашей грамматики и генерации синтаксического анализатора (скажем, в C). Такой синтаксический анализатор может быть подключен обратно к Mathematica через MathLink или LibraryLink (в случае C). Конечным результатом будет строка, которая при разборе станет действительным выражением Mathematica. Это выражение будет представлять абстрактное синтаксическое дерево вашего проанализированного кода. Например, такой код (здесь представлен новый синтаксис для Fold)

"((1|+|{2,3,4,5}))"

может быть разобран во что-то вроде

"functionCall[fold,{plus,1,{2,3,4,5}}]"

Второй компонент для такого препроцессора был бы написан на Mathematica, возможно, в стиле на основе правил, чтобы генерировать код Mathematica из AST. Полученный код должен быть как-то не оценен. Для приведенного выше кода результат может выглядеть как

Hold[Fold[Plus,1,{2,3,4,5}]]

Было бы лучше, если бы в Mathematica были доступны аналоги таких инструментов, как Lex (Flex) / Yacc (Bison) (я имею в виду привязки, для которых требуется только писать код в Mathematica и генерировать синтаксический анализатор C из этого автоматически, подключив его обратно к ядру через MathLink или LibraryLink). Я могу только надеяться, что они станут доступны в некоторых будущих версиях. В отсутствие этого подхода, который я описал, потребовалось бы много работы на низком уровне (C или Java, если вы предпочитаете). Я думаю, что это все еще выполнимо однако. Если вы можете писать на C (или Java), вы можете попробовать сделать довольно простой (с точки зрения синтаксиса / грамматики) язык - это может быть интересным проектом и даст представление о том, как он будет выглядеть для более сложного один. Я бы начал с очень простого примера калькулятора и, возможно, заменил бы стандартные арифметические операторы на более странные, которые Mathematica не может анализировать сам, чтобы сделать его более интересным. Чтобы избежать сложности MathLink / LibraryLink вначале и просто протестировать, вы можете вызвать полученный исполняемый файл из Mathematica с Run, передав код в качестве одного из аргументов командной строки, и записать результат во временный файл, который вы затем импортируете в Mathematica. Для примера калькулятора, все это можно сделать за несколько часов.

Конечно, если вы хотите сокращать только длинные имена функций, есть гораздо более простая альтернатива - вы можете использовать With для этого. Вот практический пример этого - мой порт исправления орфографии Питера Норвига , где я обманул таким образом, чтобы уменьшить количество строк:

Clear[makeCorrector];
makeCorrector[corrector_Symbol, trainingText_String] :=
Module[{model, listOr, keys, words, edits1, train, max, known, knownEdits2},
(* Proxies for some commands - just to play with syntax a bit*)
With[{fn = Function, join = StringJoin, lower = ToLowerCase, 
 rev = Reverse, smatches = StringCases, seq = Sequence, chars = Characters, 
 inter = Intersection, dv = DownValues, len = Length, ins = Insert,
 flat = Flatten, clr = Clear, rep = ReplacePart, hp = HoldPattern},
(* body *)
listOr = fn[Null, Scan[If[# =!= {}, Return[#]] &, Hold[##]], HoldAll];
keys[hash_] := keys[hash] = Union[Most[dv[hash][[All, 1, 1, 1]]]];
words[text_] := lower[smatches[text, LetterCharacter ..]];
With[{m = model}, 
 train[feats_] := (clr[m]; m[_] = 1; m[#]++ & /@ feats; m)];
 With[{nwords = train[words[trainingText]], 
  alphabet = CharacterRange["a", "z"]},
  edits1[word_] := With[{c = chars[word]}, join @@@ Join[
     Table[
      rep[c, c, #, rev[#]] &@{{i}, {i + 1}}, {i, len[c] - 1}], 
     Table[Delete[c, i], {i, len[c]}], 
     flat[Outer[#1[c, ##2] &, {ins[#1, #2, #3 + 1] &, rep}, 
       alphabet, Range[len[c]], 1], 2]]];
  max[set_] := Sort[Map[{nwords[#], #} &, set]][[-1, -1]];
  known[words_] := inter[words, keys[nwords]]]; 
 knownEdits2[word_] := known[flat[Nest[Map[edits1, #, {-1}] &, word, 2]]];
 corrector[word_] := max[listOr[known[{word}], known[edits1[word]],
   knownEdits2[word], {word}]];]];

Вам понадобится некоторый обучающий текст с большим количеством слов в виде строки для передачи в качестве второго аргумента, а первый аргумент - это имя функции для корректора. Вот тот, который использовал Норвиг:

text = Import["http://norvig.com/big.txt", "Text"];

Вы звоните один раз, говорите

In[7]:= makeCorrector[correct, text]

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

In[8]:= correct["coputer"] // Timing

Out[8]= {0.125, "computer"}

Вы можете создать свою собственную With структуру управления, в которой вы жестко закодируете короткие имена для некоторых длинных имен mma, которые вас больше всего раздражают, а затем оберните их вокруг своего фрагмента кода (вы потеряете подсветка кода однако). Обратите внимание, что я обычно не поддерживаю этот метод - я сделал это просто для забавы и немного уменьшил количество строк. Но, по крайней мере, это универсально в том смысле, что оно будет работать как в интерактивном режиме, так и в пакетах. Не может делать инфиксные операторы, не может изменять приоритеты и т. Д. И т. П., Но практически не работает.

3 голосов
/ 26 марта 2011

(мой первый ответ / пост .... будь нежным)

Исходя из моего опыта, эта функциональность кажется немного тупиком программирования. Возможность определения пользовательских обозначений в значительной степени зависит от использования «палитры обозначений» для определения и очистки каждой настраиваемой записи. («все является выражением» ... ну, за исключением некоторых непонятных случаев, таких как нотации, где вы должны использовать палитру.) Bummer.

В документации пакета Notation это явно упоминается, поэтому я не могу жаловаться слишком много.

Если вы просто хотите определить пользовательские нотации в конкретной записной книжке, нотации могут быть вам полезны. С другой стороны, если ваша цель состоит в том, чтобы внедрить пользовательские нотации в YourOwnPackage.m и распространить их среди других, вы, вероятно, столкнетесь с проблемами. (разве вы не очень хорошо разбираетесь в структурах Box?)

Если бы кто-то мог исправить мое невежество на этом, ты бы сделал мой месяц !! :)

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

3 голосов
/ 26 марта 2011

Не полный ответ, но просто для того, чтобы показать трюк, который я выучил здесь (больше, я думаю, больше относится к переопределению символов, чем к нотации):

Unprotect[Fold];
Fold[f_, x_] :=
  Block[{$inMsg = True, result},
    result = Fold[f, First@x, Rest@x];
    result] /; ! TrueQ[$inMsg];
Protect[Fold];

Fold[f, {a, b, c, d}]
(*
--> f[f[f[a, b], c], d]
*)

Редактировать

Спасибо @rcollyer за следующее (см. Комментарии ниже).

Вы можете включить или отключить определение по своему усмотрению, используя переменную $ inMsg:

$inMsg = False;
Fold[f, {a, b, c, d}]
(*
->f[f[f[a,b],c],d]
*)

$inMsg = True;
Fold[f, {a, b, c, d}]
(*
->Fold::argrx: (Fold called with 2 arguments; 3 arguments are expected. 
*)

Fold[f, {a, b, c, d}]

Это бесценно при тестировании

...