В статье Фила Уодлера «Сущность функционального программирования» Уодлер описывает применение монад с помощью простой программы-интерпретатора. Программа показана ниже:
Терм — это переменная, константа, сумма, лямбда-выражение или приложение. Следующее будет служить тестовыми данными.
term0 = (App (Lam "x" (Add (Var "x") (Var "x"))) (Add (Con 10) (Con 11)))
Для наших целей монада — это тройка
(M,unitM,bindM)
, состоящая из конструктора типаM
и пары полиморфных функций.unitM :: a -> M a bindM :: M a -> (a -> M b) -> M b
Тогда программа интерпретатора описывается как:
type Name = String
data Value = Wrong
| Num Int
| Fun (Value -> M Value)
Я не понимаю, как сюда попало M Value
. Насколько я понимаю, Haskell не допускает ограничений типов для конструкторов типов данных?
Дополнительная информация: Полная программа приведена ниже:
type Name = String
data Term = Var Name
| Con Int
| Add Term Term
| Lam Name Term
| App Term Term
data Value = Wrong
| Num Int
| Fun (Value -> M Value)
type Environment = [(Name, Value)]
interp :: Term -> Environment -> M Value
interp (Var x) e = lookup x e
interp (Con i) e = unitM (Num i)
interp (Add u v) e = interp u e `bindM` (\a ->
interp v e `bindM` (\b ->
add a b))
interp (Lam x v) e = unitM (Fun (\a -> interp v ((x,a):e)))
interp (App t u) e = interp t e `bindM` (\f ->
interp u e `bindM` (\a ->
apply f a))
lookup :: Name -> Environment -> M Value
lookup x [] = unitM Wrong
lookup x ((y,b):e) = if x==y then unitM b else lookup x e
add :: Value -> Value -> M Value
add (Num i) (Num j) = unitM (Num (i+j))
add a b = unitM Wrong
apply :: Value -> Value -> M Value
apply (Fun k) a = k a
apply f a = unitM Wrong
Как видно, interp (Lam x v) e = unitM (Fun (\a -> interp v ((x,a):e)))
требует определения data Value = ... | Func (Value -> M Value)
Я пытался реализовать interp (Lam x v)
с помощью data Value = ... | Func (Value -> Value)
, но мне это не показалось возможным.