2013-08-17 4 views
5

끔찍한 제목을 위해 죄송합니다. 나는 Monoid 유형을 포장하는 Monad에 대해 Applicative의 인스턴스를 만들려고합니다.(Monad m, Monoid o) => m o?

instance (Monad m, Monoid o) => Applicative (m o) where 
    pure x = return mempty 
    xm <*> ym = do 
     x <- xm 
     y <- ym 
     return $ x `mappend` y 

이것은 작동하지 않습니다. GCHi는 다음과 같이 불평합니다 :

Kind mis-match 
The first argument of `Applicative' should have kind `* -> *', 
but `m o' has kind `*' 
In the instance declaration for `Applicative (m o)' 

나는 위에 쓴 내용이 의미가 없다는 것을 알고 있습니다. 다음은 문맥입니다. compos 추상화를 논문 A pattern for almost compositional functions에 설명 된대로 사용하려고합니다. 이 나무 촬영 (compos의 GADT 버전을 사용하여, 나는 그것을 많이 단순화했습니다) :

data Tree :: * -> * where 
    Var :: String -> Expr 
    Abs :: [String] -> Expr -> Expr 
    App :: Expr -> [Expr] -> Expr 

class Compos t where 
    compos :: Applicative f => (forall a. t a -> f (t a)) -> t c -> f (t c) 

instance Compos Tree where 
    compos f t = 
     case t of 
      Abs ps e -> pure Abs <*> pure ps <*> f e 
      App e es -> pure App <*> f e <*> traverse f es 
      _ -> pure t 

내가 나무를 내려 기능을 많이 쓰고라는 에러 또는 목록을 반환거야 등 또한 (예 : 바인딩 환경으로) 내려갑니다 상태를 필요로하는 반면 문자열의 집합 :

composFoldM :: (Compos t, Monad m, Monoid o) => (forall a. t a -> m o) -> t c -> m o 
composFoldM f = ??? 

checkNames :: (Tree a) -> State (Set Name) [Error] 
checkNames e = 
    case e of 
     Var n -> do 
      env <- get 
      -- check that n is in the current environment 
      return $ if Set.member n env then [] else [NameError n] 
     Abs ps e' -> do 
      env <- get 
      -- add the abstractions to the current environment 
      put $ insertManySet ps env 
      checkNames e' 
     _ -> composFoldM checkNames e 

data Error = NameError Name 
insertManySet xs s = Set.union s (Set.fromList xs) 

나는이 모든 (Monad m, Monoid o) => m o 구조 composFoldM 사용 compos함으로써 멀리 추상화 될 수 있어야한다고 생각합니다. GADT Applicative 버전을 compos 페이지와 함께 사용하려면 페이지 575/576에서 the paper을 사용하세요. 이 구조의 Applicative 인스턴스를 만들어야한다고 생각합니다. 어떻게하면 좋을까요? 아니면 잘못된 길로 완전히 빠져드는거야?

답변

5

패키지의 신청자가 Data.Functor.Constant 인 경우 here을 찾으십시오.

instance (Monoid a) => Applicative (Constant a) where 
    pure _ = Constant mempty 
    Constant x <*> Constant y = Constant (x `mappend` y) 

당신은 다음 here을 찾을 수 있습니다합니다 (transformers 패키지도) ComposeData.Functor.Compose에서 사용하는 다른 실용적으로 Constant을 구성 할 수 있습니다

Applicative 다음과 같은 경우가 있습니다.

instance (Applicative f, Applicative g) => Applicative (Compose f g) where 
    pure x = Compose (pure (pure x)) 
    Compose f <*> Compose x = Compose ((<*>) <$> f <*> x) 

그런 다음 Compose 다른 ApplicativeConstant 실용적 (같은 State)는 일부 상태 및 실행 Monoid 집계을 모두 유지 할 수 있습니다

ComposeApplicative 인스턴스를가집니다.

더 일반적으로이 패턴에 대해 자세히 설명하는 The Essence of the Iterator Pattern 용지를 읽어야합니다.

+0

내가 필요한 것 같습니다. 하지만 어떻게 실제로 사용합니까? 나는'composFoldM f = getCompose '와 같은 일을 시도했다. compos (WrapMonad, Const. f)를 작성하십시오. '하지만이 방법은 효과가 없습니다. 펑터를 결합하는 방법에 대한 예/설명이 있습니까? –

+0

나의 신. 나는 시험과 개선을 통해 그것을 마침내 해결했다. 나는 이것이 당신이 배우는 방법이라고 생각한다! 올바른 것은'composFoldM f = liftM getConst. unwrapMonad. getCompose. compos (WrapMonad. liftM Const. f)를 작성하십시오. : D –

+1

@CallumRogers 그게 맞아! 그것은 하스켈에 관한 좋은 점 중 하나입니다. 유형 검사기는 항상 올바른 해결책을 제시 할 것입니다. –

관련 문제