2012-02-15 2 views
0

의 내가 지금 계산 모나드 명령을 인수로 취하는 함수에서 모나드 변환기를 지원하는 가장 좋은 방법은 무엇입니까?

class A where 
    foo :: () -> () 

instance A IO where 
    foo x = do 
     print "prefix" 
     x 
     print "suffix" 
있다고 가정 해 봅시다, 내가 예를 들어 인수를, "풀다"강제하고있어 foo을 구현 내가, 그리고

instance A => A (MyMonadTransformerT γ) 

를 작성한다고 가정 foo x = lift (foo (unlift x)). 이 unlift 함수는 모나드 계산에 좋지 않을 수 있습니다. 주 변압기의 경우 프로그램 상태의 변경 사항을 잊어 버리게됩니다.

리프팅 함수를 사용하는 좀 더 일반적인 방법을 만드는 것으로 작동하며 t() -> t()이라는 계산 결과를 얻습니다. 여기서 t은 해제 된 (변환 된) 모나드입니다.

class Monad => A' where 
    foo' :: Monad t => 
     (forall z . z -> t z) -- lifting function 
     -> t() 
     -> t() 
    foo :: () -> () 
    foo = foo' id 

instance A' IO where 
    foo' lift x = do 
     lift (print "prefix") 
     x 
     lift (print "suffix") 

instance A' => A' (StateT γ) where 
    foo' lift' x = foo' (lift' . lift) x 

computation :: Num a => StateT a IO() 
computation = do 
    foo (put 1 >> lift (print "middle")) 
    v <- get 
    lift $ print ("value", v) 

run_computation :: Num a => IO a 
run_computation = execStateT computation 0 

질문. 이것이 최선의 방법입니까? 좀 더 일반적인 글을 쓸 수 있습니까? CPS 스타일 코드? 감사!!

+2

가능한 한 [하스켈에서 고차 함수 해제하기] (0120-367-304) –

+0

네, 중복 된 것 같아요. . "수업을 재촉하는 것"I와 luqui가 가장 좋은 것 같았습니다. – gatoatigrado

답변

2

먼저, class 사업을 잊어 버리면 기능이 필요한 것처럼 보입니다. 당신이 IO를 할 수있는 모나드 계산을 가지고 있지만, 다른 일을하도록 허용하는 경우, 당신은 형식 매개 변수 m 어떤 모나드로 걸릴 것이다 그래서 MonadIO, MonadState 등 :

이 문제는 Monad* 클래스에 의해 다루어진다 이는 IO 작업을 수행 할 수 있습니다 :

foo :: (MonadIO m) => m() -> m() 
foo x = do 
    liftIO $ putStrLn "prefix" 
    x 
    liftIO $ putStrLn "suffix" 

가 지금은 m이 무엇인지는 중요하지 않습니다, MonadIO 원하는 작업에 다시 들어하는 방법을 말한다 때문이다.

Monad* 클래스는 새로운 변압기에도 불구하고 다소 모듈 형이 아닙니다. 필요한 인스턴스의 수는 모나드 변환기 수에 2 차입니다. 이 문제에 대한 여러 차선책이 있습니다. 그러한 문제가 걱정된다면 언제든지 클래스를 구체화 할 수 있습니다.

foo :: (Monad m) => (forall a. IO a -> m a) -> m() -> m() 
foo lift x = do 
    lift $ putStrLn "prefix" 
    x 
    lift $ putStrLn "suffix" 

이렇게할지 여부는 추상화 수준에 따라 다릅니다. 콘텐츠 코드를 작성할 라이브러리를 작성하는 경우 전자를, 다른 라이브러리 코드를 빌드 할 라이브러리를 작성하는 경우 후자를 원할 것입니다. 모나드 스택이 출퇴근하지 않기 때문에 어느 쪽이든 까다로울 수 있습니다.

+0

클래스의 다른 인스턴스를 표시하지 않았습니다. 그렇습니다. 클래스를 원하지만'foo '만이'foo'는 함수 여야합니다. 게다가 컴파일러는 '리프트'(1 모나드 변압기), '리프트'를 사용할지 여부를 추측 할 수 없습니다. 리프트 (2 모나드 변압기) 등. – gatoatigrado

관련 문제