Подтвердить что ты не робот

Аппликационный пример для MaybeT m предполагает Monad m

Я использовал монаду Haxl (описанную здесь: http://www.reddit.com/r/haskell/comments/1le4y5/the_haxl_project_at_facebook_slides_from_my_talk), у которой есть интересная функция, которая <*> для своего аппликативного экземпляра isn 't то же, что и ap из Control.Monad. Это ключевая функция, позволяющая выполнять параллельные вычисления без блокировки. Например, если hf и ha являются длинными вычислениями, то

let hf :: Haxl (a -> b) = ...
    ha :: Haxl a = ...
in do
  f <- hf
  a <- ha
  return (f a)

будет выполнять их последовательно, а

hf <*> ha

будет выполнять их параллельно, а затем объединить результаты.

Я хотел бы иметь возможность запускать вычисления в MaybeT Haxl, но проблема в том, что аппликативный экземпляр для MaybeT m в пакете трансформаторов использует монадическое связывание:

instance (Functor m, Monad m) => Applicative (MaybeT m) where
    pure = return
    (<*>) = ap

Где ap = liftM2 id - от Control.Monad. Это делает

let hmf :: MaybeT Haxl (a -> b) = ...
    hma :: MaybeT Haxl a = ...
in hmf <*> hma

запускается последовательно. Кажется, что лучший пример будет больше похож на

instance (Applicative m) => Applicative (MaybeT m) where
    pure = MaybeT . pure . Just
    MaybeT f <*> MaybeT x = MaybeT $ (<*>) <$> f <*> x

(Здесь (<*>) в правой части для монады Maybe, а в скобках <*> в правой части для m.) Обратите внимание, что контекст отличается - вышеупомянутый экземпляр принимает только Applicative m, а экземпляр в трансформаторах принимает Functor m, Monad m.

Мой главный вопрос практичен: что мне делать с этим? Должен ли я запускать собственный трансформатор монады MaybeT? Есть ли способ обойти жалобу "Повторяющиеся экземпляры экземпляра", которую ghc дает мне, если я попытаюсь написать выше?

Я также хотел бы знать: является ли текущая установка дефектом дизайна в пакете трансформаторов? Если нет, почему бы и нет?

4b9b3361

Ответ 1

Фокус в том, что (в отличие от монад) аппликативные функторы являются составными, поэтому вам не нужны (аппликативные) трансформаторы, такие как MaybeT. Вместо этого вы можете использовать Compose для объединения двух аппликативных функторов:

import Control.Applicative
import Data.Functor.Compose

type HaxlM = Compose Haxl Maybe

-- if you prefer to have a function for constructing values:
haxlM :: Haxl (Maybe a) -> HaxlM a
haxlM = Compose

Композиция всегда является правильным экземпляром Applicative и использует только экземпляр Applicative своих компонентов. Например:

test = getZipList . getCompose
       $ (+) <$> Compose (ZipList [Just 1,  Nothing, Just 3])
             <*> Compose (ZipList [Nothing, Just 20, Just 30])

создает [Nothing,Nothing,Just 33].