2013-09-07 3 views
14

저는 현재 Data.FreshControl.Monad.Trans.Fresh으로 일하고 있습니다. 새로운 변수를 생성하기위한 인터페이스와이 인터페이스를 구현하는 모나드 변환기를 정의한다.`(Applicative m) => Applicative (StateT s m)`을 구현할 수 있습니까?

처음에는 FreshT v mApplicative 인스턴스를 구현할 수 있다고 생각했지만 Applicative m이라는 유일한 요구 사항이 있습니다. 그러나 나는 갇혀있어 Monad m을 필요로하는 것처럼 보였다. 내 하스켈-FU를 신뢰하지, 내가 다음 변압기 패키지로 전환, 나는 Control.Monad.Trans.State.Lazy.Strict에있는 것을 놀랐다 : 그래서 여기

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

내 질문은 :이되어 가능한 동등한 의미를 가진 인스턴스를 생성 다음 인스턴스 헤드?

instance (Applicative m) => Applicative (StateT s m) where 
+0

흥미롭게도, 다른 변압기가있다 (예를 들어,'WriterT','ExceptT'), 그' Applicative 인스턴스는 기본 타입 생성자가 Monad이어야합니다. – kirelagin

답변

12

는 두 가지 기능을 가지고 생각해 보면 f에 전달할 수있는

f :: s -> m (s, a -> b) 
g :: s -> m (s, a) 

을 그리고 당신은 당신 위는 s을에서 함수 h = StateT f <*> StateF g

h :: s -> m (s, b) 

를 만들 그래서 당신을 have :

f' :: m (s, a -> b) 
g :: s -> m (s, a) 

그러나 f'에서 s을 얻으려면 모나드가 필요합니다 (응용 프로그램과 관련이 있다면 m s의 형식이어야하므로 g에 값을 적용 할 수 없음).

정의로 게임을하고 free monad을 사용할 수 있지만 상태가 무너지면 join이 필요합니다. 이전 답변에 명시된 바와 같이,이 경우는, 일반적으로 정의 할 수 있지만

+0

필자는 이미'm (m a)'와 계속해서 대면했기 때문에 이미 그렇게 생각했습니다. –

+1

@Rhymoid :'a -> b '부분을 건너 뛰면'f':: m s'와'g :: s -> m b'가됩니다. 그러므로'StateT'에'<*>'을 구현하면's'가 임의적 일 수 있다고 가정 할 때'm ='에 대해'>> ='의 구현을 제공합니다. –

+0

틀림없이 이것이 틀린가요? StateT는 모나드이므로, 정의에 따라 그것은 Applicative이며, 표준 라이브러리에서 단순히'(<*>) = ap'라고 말합니다. 그러나 이것이 의미하는 것은 당신이'(<*>)'을 직접 구현할 수 있어야한다는 것입니다. 내부 응용 프로그램으로부터'(<*>)'또는'fmap' 만 사용하면됩니다. 문제는 내가 어떻게하는지 알 수 없다는 것이다. –

5

그것은 주목할 가치가 그 fApplicative이며이 조성물로 간주 될 수 있기 때문에 sStateT s fApplicative이다하는 Monoid 때 실용적으로 펑 일 : Applicative 변압기

StateT s f = Reader s `Compose` f `Compose` Writer s 
+0

'StateT'와 관련하여 정의한이 적용 가능한 함수기는 정확히 얼마나됩니까? – kirelagin

4

약한 변형

StateT위한 실용적 변환기를 정의하는 것이 가능하지 않지만, 그것은 것이 가능 작동하는 약한 변형을 정의하십시오. 상태가 s -> m (a, s) 인 대신 다음 상태를 결정 (따라서 m은 모나드 여야 함)하고 m (s -> (a, s)) 또는 이와 동등하게 m (State s a)을 사용할 수 있습니다.

import Control.Applicative 
import Control.Monad 
import Control.Monad.State 
import Control.Monad.Trans 

newtype StateTA s m a = StateTA (m (State s a)) 

StateT보다 확실히 약하다.모든 StateTAStateT로했다 (하지만 그 반대의 경우도 마찬가지) 할 수 있습니다 FunctorApplicative 정의

toStateTA :: Applicative m => StateTA s m a -> StateT s m a 
toStateTA (StateTA k) = StateT $ \s -> flip runState s <$> k 

m 기본으로 State의 동작을 올리는 단지 문제이다 :

instance (Functor m) => Functor (StateTA s m) where 
    fmap f (StateTA k) = StateTA $ liftM f <$> k 
instance (Applicative m) => Applicative (StateTA s m) where 
    pure = StateTA . pure . return 
    (StateTA f) <*> (StateTA k) = StateTA $ ap <$> f <*> k  

우리가 정의 할 수 있습니다 lift의 실용적 변형 :

lift :: (Applicative m) => m a -> StateTA s m a 
lift = StateTA . fmap return 

업데이트 : 실제로 두 개의 응용 펑터의 구성은 항상 모나드와 달리 적용 가능한 펑터이므로 위의 것은 필요하지 않습니다. 우리 StateTA 자동 ApplicativeCompose m (State s)에 동형 :

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

우리가 쓸 수있는 단지

{-# LANGUAGE GeneralizedNewtypeDeriving #-} 
import Control.Applicative 
import Control.Monad.State 
import Data.Functor.Compose 

newtype StateTA s m a = StateTA (Compose m (State s) a) 
    deriving (Functor, Applicative) 
+0

매우 흥미 롭습니다. 내 응용 프로그램에서는 국가 자체 (새로운 가치의 공급)가 반드시 다음 효과를 결정하지 않으며, 얼마나 자주 복제되고 추출되는지. 내 구현 중 하나는이 문제를 해결할 수 있지만 다른 하나는 아직 해결할 수 없습니다. 아마도이 대답은 유용 할 수 있습니다. 감사! –