Почему оператор let позволяет блоку «Applicative do» требовать ограничения монадой? - PullRequest
5 голосов
/ 06 октября 2019

Рассмотрим этот пример:

{-# language ApplicativeDo #-}

module X where

data Tuple a b = Tuple a b deriving Show

instance Functor (Tuple a) where
    fmap f (Tuple x y) = Tuple x (f y)

instance Foldable (Tuple a) where
    foldr f z (Tuple _ y) = f y z

instance Traversable (Tuple a) where
    traverse f (Tuple x y) = do
        y' <- f y
        let t' = Tuple x y'
        return $ t'

Выглядит хорошо! Но нет:

[1 of 1] Compiling X                ( X.hs, interpreted )

X.hs:15:9: error:
    • Could not deduce (Monad f) arising from a do statement
      from the context: Applicative f
        bound by the type signature for:
                   traverse :: forall (f :: * -> *) a1 b.
                               Applicative f =>
                               (a1 -> f b) -> Tuple a a1 -> f (Tuple a b)
        at X.hs:14:5-12
      Possible fix:
        add (Monad f) to the context of
          the type signature for:
            traverse :: forall (f :: * -> *) a1 b.
                        Applicative f =>
                        (a1 -> f b) -> Tuple a a1 -> f (Tuple a b)
    • In a stmt of a 'do' block: y' <- f y
      In the expression:
        do y' <- f y
           let t' = Tuple x y'
           return $ t'
      In an equation for ‘traverse’:
          traverse f (Tuple x y)
            = do y' <- f y
                 let t' = ...
                 return $ t'
   |
15 |         y' <- f y
   |         ^^^^^^^^^
Failed, no modules loaded.

Даже если это не удается:

instance Traversable (Tuple a) where
    traverse f (Tuple x y) = do
        y' <- f y
        let unrelated = 1
        return $ Tuple x y'

Итак, введение любого оператора let удаляет «аппликативное» из ». аппликативное "" 1014 *. Почему?

Ответы [ 2 ]

5 голосов
/ 06 октября 2019

Это будет переводиться в

let unrelated = 1 in return $ Tuple x y'

, который не имеет формы return <something>, а аппликативный do требует, чтобы последний оператор был return или pure:

В общем случае правило, когда для оператора do накладывается ограничение Monad, заключается в следующем. Если выражение do имеет следующую форму:

do p1 <- E1; ...; pn <- En; return E

, где ни одна из переменных, определенных p1...pn, не упоминается в E1...En, а p1...pn - все переменные или ленивые шаблоны, тогда выражениепотребуется только Applicative. В противном случае для выражения потребуется Monad. Блок может возвращать чистое выражение E в зависимости от результатов p1...pn с return или pure.

Примечание: конечный оператор должен точно соответствовать одному из следующих шаблонов:

return E
return $ E
pure E
pure $ E

в противном случае GHC не может распознать его как оператор возврата, и преобразование для использования <$>, которое мы видели выше, не применяется. В частности, небольшие изменения, такие как return . Just $ x или let x = e in return x, не будут распознаны.

Если вы посмотрите описание десугарирования в https://gitlab.haskell.org/ghc/ghc/wikis/applicative-do,, оно также не поддерживает let никак.

4 голосов
/ 06 октября 2019

Какое аппликативное выражение вы бы хотели, чтобы это описывало? Монадическое выражение представляет собой серию связанных областей, поэтому для let имеет смысл ввести привязку, которая распространяется на все оставшиеся области, но с помощью аппликативных различные выражения не могут действительно зависеть друг от друга, поэтому здесь нет области видимости. что имеет смысл десугар let в.

...