Изучение внутренних функций в Haskell - PullRequest
7 голосов
/ 14 февраля 2009

Я новичок в Haskell, хотя уже имел опыт работы с 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 ]

6 голосов
/ 14 февраля 2009

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

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

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

derive :: Expression -> Expression

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


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

4 голосов
/ 14 февраля 2009

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

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

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

1 голос
/ 14 февраля 2009

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

Тем не менее, дальнейшее приближение к Google оказалось Liskell , который (?) Интересный гибрид.

...