Изучение внутренних функций в Хаскелле


Я новичок в Хаскелле, хотя и имел предыдущий опыт работы с Lisp/Scheme. Прямо сейчас я смотрю на примеры из SICP и пытаюсь реализовать их в Haskell, чтобы получить больше практического опыта. В лекции 3b авторы представляют функцию для вычисления производных символически. Он содержит, среди прочего, следующие строки:

(define (deriv exp var)
    (cond ((constant? exp var) 0)
          ((same-var? exp var) 1)
; ...

Далее в лекции определяются еще некоторые функции:

(define (constant? exp var)
    (and (atom? exp)
         (not (eq? exp var))))

Есть ли способ сделать то же самое в Haskell, т. е. проверить атомарность а символическая эквивалентность какой-то другой функции? Или в более общем плане, каковы средства "разборки" функций в Haskell?

3 7

3 ответа:

Ваши примеры схем на самом деле не исследуют функции схемы. Недавно я провел некоторую символическую дифференциацию в Haskell по значениям следующего типа:

data Exp a = Lit a
           | Exp a :*: Exp a
           | Exp a :+: Exp a
           | Var String
  deriving Eq

Вместо различения с помощью atom? или eq? вы используете case (или другое сопоставление шаблонов) и ==.

Во-первых, хотя SICP велик, я бы рекомендовал не использовать его для изучения Хаскелла.( # ) Некоторые трудности в этом вопросе проистекают из этого.

В Lisp/Scheme "функция" мыслится как часть кода, и изучение функции просто означает изучение ее кода. В Haskell, A 'function' означает нечто более близкое к его математическому определению, как отображение из множества A в множество B. Так, например, в контексте Lisp имеет смысл сравнить две функции: просто сравните их код. (Но являются ли (x+y)^2 и x^2+2*x*y+y^2 различными функциями?) В Хаскелле это зависит от того, существует ли конструктивная процедура определения равенства для рассматриваемого класса функций.

Точно так же, как и в вашем вопросе, в Lisp/Scheme вы бы написали функцию "derive", которая правильно дифференцирует заданные выражения и просто выдает ошибки или возвращает мусор на произвольных входах. В соответствии с системой типов Хаскелла это (AFAIK) невозможно сделать, потому что-если вы думаете об этом-нет такой вещи, как дифференцирование произвольного входного сигнала: вы можете дифференцировать только выражение (или, возможно, более общий класс, но все же не все). Итак, как и в ответе Нормана Рэмси, вы сначала определяете тип "выражения" (или класс типа), что очень просто сделать, а затем пишете функцию
derive :: Expression -> Expression

, который разбирает Expression, используя соответствующие шаблону конструкции (или что-то еще в зависимости от того, как были построены Expression s).


(#): причина в том, что SICP имеет совершенно иную философию, которая предполагает использование нетипизированного языка программирования и поощряет отсутствие различия между кодом и данными. Хотя аргумент "код=данные" имеет некоторые достоинства (например, тот факт, что в архитектуре фон Неймана мы используем "все равно 0 и 1"), это не обязательно хороший способ рассуждения о проблемах или моделирования. (Подробнее об этом см. статью Филиппа Уодлера " почему расчет лучше, чем интрига".) Если хотите для чтения книги Хаскелла с функциональным вкусом вместореального мира , возможно, лучшим выбором будет книга Саймона ТомпсонаHaskell: the Craft of Functional Programming или Ричарда Бердавведение в функциональное программирование с использованием Haskell .

Я не думаю, что ты сможешь это сделать. Лисп-это гомойконический , Хаскелл-нет.

Однако, дальнейшее гугление оказалось Liskell , который (?) интересный гибрид.