Я работал через превосходное Программирование на Haskell (2-е изд) . Однако я немного озадачен вопросом об аппликативах.
Дан следующий тип:
data Expr a = Var a | Val Int | Add (Expr a) (Expr a) deriving Show
Вопрос заключается в написании реализаций классов Functor
, Applicative
и Monad
.
Functor
прост, как и Monad
(по крайней мере, это компилируется, я еще не полностью обернул голову вокруг этого, но я больше беспокоюсь об этом в первую очередь).
Я придумал это, которое компилируется, но у меня есть проблемы:
instance Applicative Expr where
-- pure :: a -> Expr a
pure = Var
-- (<*>) :: Expr (a -> b) -> Expr a -> Expr b
(Var fab) <*> fa = fmap fab fa
pure
нормально, но меня беспокоит фактический аппликативный оператор <*>
. Насколько я могу судить, это имеет смысл только для Var
, но не для Val
или Add
. И мне просто странно, что у вас есть тип, в котором допустимо выражать вещи, которые могут взорваться - например, у вас может быть Add (Var ord) (Val 10)
, который имеет тип Expr (Char -> Int)
, поэтому проверка типов будет выполнена как lhs в <*>
выражение, но (как оно есть) взорвется. И мне не ясно, как будет работать рекурсивное определение - потому что, как только вы нажмете (Val 10)
, вы набиты - нет никакого способа преобразовать rhs в необходимый тип.
Что мне здесь не хватает? Как мне завершить определение <*>
так, чтобы вещи не взорвались, и это все еще действительный аппликатив? Правильно ли я думаю / чувствую, что на самом деле вы бы не создали такой тип?
Спасибо!