Mathematica: что такое символическое программирование? - PullRequest
77 голосов
/ 13 декабря 2010

Я большой поклонник Стивена Вольфрама, но он определенно не стесняется надевать свой рогВо многих ссылках он превозносит Mathematica как другую символическую парадигму программирования.Я не пользователь Mathematica.

Мои вопросы: что это за символическое программирование?И как это соотносится с функциональными языками (такими как Haskell)?

Ответы [ 5 ]

73 голосов
/ 14 декабря 2010

Когда я слышу фразу "символическое программирование", LISP, Prolog и (да) Mathematica сразу же приходят на ум.Я бы охарактеризовал символическую среду программирования как среду, в которой выражения, используемые для представления текста программы, также являются основной структурой данных.В результате становится очень легко создавать абстракции на основе абстракций, поскольку данные могут быть легко преобразованы в код и наоборот.

Mathematica активно использует эту возможность.Даже в большей степени, чем LISP и Prolog (IMHO).

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

r,1,2
g,3,4

Я прочитал этот файл в:

Import["somefile.csv"]
--> {{r,1,2},{g,3,4}}

Являются ли данные результата или код?Это оба.Это данные, которые получаются при чтении файла, но это также и выражение, которое будет создавать эти данные.Однако, как показывает код, это выражение является инертным, поскольку результатом его оценки является просто само по себе.

Поэтому теперь я применяю преобразование к результату:

% /. {c_, x_, y_} :> {c, Disk[{x, y}]}
--> {{r,Disk[{1,2}]},{g,Disk[{3,4}]}}

Не останавливаясь на деталяхвсе, что произошло, это то, что Disk[{...}] обернуто вокруг двух последних чисел в каждой строке ввода.Результат все еще данные / код, но все еще инертен.Еще одно преобразование:

% /. {"r" -> Red, "g" -> Green}
--> {{Red,Disk[{1,2}]},{Green,Disk[{3,4}]}}

Да, все еще инертно.Однако, по удивительному стечению обстоятельств, этот последний результат оказался списком допустимых директив во встроенном в Mathematica доменно-ориентированном языке для графики.Последнее преобразование, и вещи начинают происходить:

% /. x_ :> Graphics[x]
--> Graphics[{{Red,Disk[{1,2}]},{Green,Disk[{3,4}]}}]

На самом деле, вы не увидите этот последний результат.В эпическом представлении синтаксического сахара Mathematica показала бы эту картину с красными и зелеными кружками:

alt text

Но веселье на этом не заканчивается.Под всем этим синтаксическим сахаром у нас все еще есть символическое выражение.Я могу применить другое правило преобразования:

% /. Red -> Black

alt text

Presto!Красный круг стал черным.

Именно этот вид «проталкивания символов» характеризует символическое программирование.Подавляющее большинство программ Mathematica имеет такую ​​природу.

Функциональное или символическое

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

Можно рассматривать символическое программирование как ответ на вопрос: «Что бы произошло, если бы я попытался смоделировать все, используя только преобразования выражений?»Функциональное программирование, напротив, можно рассматривать как ответ на вопрос: «Что бы произошло, если бы я попытался смоделировать все, используя только функции?»Функциональное программирование, как и символическое программирование, позволяет быстро создавать слои абстракций.Пример, который я привел здесь, может быть легко воспроизведен, скажем, в Haskell с использованием подхода функциональной реактивной анимации.Функциональное программирование - это все о композиции функций, функциях более высокого уровня, комбинаторах - все эти изящные вещи, которые вы можете делать с функциями.

Mathematica явно оптимизирована для символического программирования.Можно написать код в функциональном стиле, но функциональные возможности в Mathematica на самом деле являются лишь тонким слоем по сравнению с преобразованиями (и в этом утечку, см. Сноску ниже).

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

Заключительные замечания

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


Утечка функциональной абстракции в Mathematica?,Попробуйте это, например: f[x_] := g[Function[a, x]]; g[fn_] := Module[{h}, h[a_] := fn[a]; h[0]]; f[999] Должным образом доложено и подтверждено WRI. Ответ: избегайте использования Function[var, body] (Function[body] в порядке).

72 голосов
/ 14 декабря 2010

Вы можете думать о символическом программировании Mathematica как о системе поиска и замены, в которой вы программируете, задавая правила поиска и замены.

Например, вы можете указать следующее правило

area := Pi*radius^2;

В следующий раз, когда вы используете area, он будет заменен на Pi*radius^2. Теперь предположим, что вы определили новое правило

radius:=5

Теперь, когда вы используете radius, оно будет переписано в 5. Если вы оцените area, он будет переписан в Pi*radius^2, который запускает правило перезаписи для radius, и вы получите Pi*5^2 в качестве промежуточного результата. Эта новая форма вызовет встроенное правило перезаписи для операции ^, поэтому выражение будет переписано в Pi*25. На этом этапе перезапись прекращается, потому что нет применимых правил.

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

add[a_,b_]:=a+b

Теперь add[x,y] переписывается в x+y. Если вы хотите добавить, чтобы применить только для числовых a, b, вы могли бы вместо этого сделать

add[a_?NumericQ, b_?NumericQ] := a + b

Теперь add[2,3] переписывается в 2+3, используя ваше правило, а затем в 5, используя встроенное правило для +, тогда как add[test1,test2] остается неизменным.

Вот пример интерактивного правила замены

a := ChoiceDialog["Pick one", {1, 2, 3, 4}]
a+1

Здесь a заменяется на ChoiceDialog, который затем заменяется числом, выбранным пользователем в появившемся диалоговом окне, что делает числовое количество и запускает правило замены для +. Здесь ChoiceDialog как встроенное правило замены в соответствии с «заменить ChoiceDialog [некоторые вещи] значением кнопки, которую пользователь нажал».

Правила могут быть определены с использованием условий, которые сами должны пройти через переписывание правил для получения True или False. Например, предположим, что вы изобрели новый метод решения уравнений, но вы думаете, что он работает только тогда, когда конечный результат вашего метода положительный. Вы могли бы сделать следующее правило

 solve[x + 5 == b_] := (result = b - 5; result /; result > 0)

Здесь solve[x+5==20] заменяется на 15, но solve[x + 5 == -20] не изменяется, потому что нет применимых правил. Условие, которое запрещает применение этого правила: /;result>0. По сути, Evaluator ищет потенциальные результаты применения правил, чтобы решить, стоит ли их использовать.

Оценщик Mathematica жадно переписывает каждый паттерн с одним из правил, применимых к этому символу. Иногда вы хотите иметь более точный контроль, и в таком случае вы можете определить свои собственные правила и применить их вручную, как это

myrules={area->Pi radius^2,radius->5}
area//.myrules

Это будет применять правила, определенные в myrules, пока результат не перестанет изменяться. Это очень похоже на оценщик по умолчанию, но теперь вы можете иметь несколько наборов правил и применять их выборочно. Более продвинутый пример показывает, как создать Prolog-подобный оценщик, который ищет последовательности приложений правил.

Один недостаток текущей версии Mathematica возникает, когда вам нужно использовать оценщик по умолчанию Mathematica (чтобы использовать Integrate, Solve и т. Д.) и , чтобы изменить последовательность оценки по умолчанию. Это возможно, но сложно , и мне нравится думать, что в будущем реализация символического программирования будет иметь более элегантный способ управления последовательностью вычислений

9 голосов
/ 14 декабря 2010

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

http://code.google.com/p/pure-lang/wiki/Rewriting

6 голосов
/ 13 декабря 2010

Mathematica активно использует переписывание терминов. Язык обеспечивает специальный синтаксис для различных форм переписывания, специальную поддержку правил и стратегий. Парадигма не такая уж «новая» и, конечно, она не уникальна, но они определенно находятся на переднем крае этой вещи «символического программирования», наряду с другими сильными игроками, такими как Аксиома.

Что касается сравнения с Haskell, то вы могли бы переписать его там, с помощью небольшой помощи из вашей шаблонной библиотеки, но это не так просто, как в динамически набираемой Mathematica.

0 голосов
/ 31 августа 2018

Символическое не должно противопоставляться функционалу, оно должно противопоставляться числовому программированию.Рассмотрим в качестве примера MatLab против Mathematica.Предположим, я хочу характеристический полином матрицы.Если бы я хотел сделать это в Mathematica, я мог бы получить матрицу тождества (I) и саму матрицу (A) в Mathematica, а затем сделать это:

Det[A-lambda*I]

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

Так вот в чем разница, символические языки заинтересованы в выполнении вычисленийс идеальной точностью (часто с использованием рациональных чисел, а не числовых), а языки числового программирования, с другой стороны, очень хорошо справляются с подавляющим большинством вычислений, которые вам нужно будет выполнять, и они, как правило, работают быстрее с числовыми операциями, для которых они предназначены.(MatLab практически не имеет себе равных в этом отношении для языков более высокого уровня - исключая C ++ и т. Д.), И он очень слаб в символических операциях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...