Поймите аппликативную проблему (# 7) в главе 12 «Программирование на Haskell» - PullRequest
0 голосов
/ 18 января 2019

Я работал через превосходное Программирование на 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 в необходимый тип.

Что мне здесь не хватает? Как мне завершить определение <*> так, чтобы вещи не взорвались, и это все еще действительный аппликатив? Правильно ли я думаю / чувствую, что на самом деле вы бы не создали такой тип?

Спасибо!

1 Ответ

0 голосов
/ 18 января 2019
Val :: Int -> Expr a

для любой a. Так

Val x <*> _ = Val x

действителен, как

_ <*> Val y = Val y

как есть

Val x <*> Val y = Val (something about x and y)

так что, к сожалению, теперь у вас есть выбор, что означает, что вы собираетесь сделать неправильный выбор. К счастью, только один из них совместим с экземпляром Monad (какой?).

Что касается рекурсивного случая, у вас есть

Add e e' <*> fb = ...
     -- e :: Expr (a -> b)
     -- e' :: Expr (a -> b)
     -- fb :: Expr a

И вы должны использовать всю входящую информацию, чтобы сделать Expr b, а также сохранить «структуру» (Add). Каким образом вы можете сделать Expr b из этого (помните, что вы можете использовать аппликативный оператор рекурсивно)?

...