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

Я использую Haxl монада (описана здесь: http://www.reddit.com/r/haskell/comments/1le4y5/the_haxl_project_at_facebook_slides_from_my_talk), которая имеет интересную особенность, которая <*> для его Applicative экземпляр не совпадает с 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 монадный трансформатор? Есть ли способ обойти жалобу "Duplicate instance messages", которую мне дает ghc, если я пытаюсь написать выше?

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

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],

Другие вопросы по тегам