Не очень конструктивный ответ, просто пара мыслей. Во-первых, отказ от ответственности - я не предлагаю какой-либо из методов, описанных ниже, в качестве хороших практик (возможно, в общем случае, нет), это всего лишь некоторые возможности, которые, кажется, решают ваш конкретный вопрос. Что касается заявленной цели - я очень поддерживаю эту идею, возможность уменьшить многословие - это здорово (по крайней мере, для личных нужд индивидуального разработчика). Что касается инструментов: у меня очень мало опыта работы с пакетом 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, которые вас больше всего раздражают, а затем оберните их вокруг своего фрагмента кода (вы потеряете подсветка кода однако). Обратите внимание, что я обычно не поддерживаю этот метод - я сделал это просто для забавы и немного уменьшил количество строк. Но, по крайней мере, это универсально в том смысле, что оно будет работать как в интерактивном режиме, так и в пакетах. Не может делать инфиксные операторы, не может изменять приоритеты и т. Д. И т. П., Но практически не работает.