2011-08-10 3 views
8

난수 생성기를 사용하고 이에 기반한 배열 및 기타 구조를 수정할 코드 (Metropolis-Hastings MCMC 샘플러)를 작성 중입니다. 내 초기 아이디어ST 모나드에서 기능들 사이의 여러 참조를 추적하는 좋은 방법은 무엇입니까?

내가 국가의 일환으로 PureMT 생성기를 유지, ST 배열과 메르 센 - 랜덤 pure64 패키지를 사용할 수 있도록 ST 모나드를 사용하는 것이 었습니다.

그러나 나는 (예를 들어, 배열 구조를 업데이트, 주어진 범위에서 임의의 정수를 샘플링하고, 잠재적으로 더 복잡한 것들) 별도의 도우미 기능으로 작업의 일부를 분할 할 수 있어야합니다. 이렇게하기 위해서는 PureMT gen과 배열에 대한 참조를 모든 함수에 전달해야 할 필요가 있다고 생각합니다. 더 많은 상태를 저장해야하는 경우에는 매우 추악해질 수 있습니다.

본능적으로 모든 상태를 하나의 데이터 유형으로 그룹화하여 새 데이터 유형을 정의하여 주 모나드를 사용할 때와 같이 어디에서나 액세스 할 수 있지만 ST에서 가능한지 여부는 알 수 없습니다 모나드, 또는 그것에 대해 갈 올바른 방법.

이런 종류의 일을하기에 좋은 패턴이 있습니까? 가능한 한 일반적인 것을 유지하고 싶습니다. 아마도 추가 상태를 추가하고 기존 파트 주변에 모나드 코드를 추가해야 할 필요가 있기 때문입니다.

나는 ST 모나드 코드의 예를 찾고 시도했지만 실제 세계 하스켈에 포함하지 않는 것, 그리고 하스켈 위키 예는 매우 짧고 간단합니다.

감사합니다.

답변

10

본능은 모든 상태를 하나의 데이터 유형으로 그룹화하여 새로운 모 형 유형을 정의하여 상태 모나드를 사용할 수 있기 때문에 어디에서나 액세스 할 수 있지만 그럴 수 있는지 여부는 알 수 없습니다 ST 모나드, 또는 그것에 대해 갈 올바른 방법. 이런 종류의 작업을 수행하기위한 어떤 좋은 패턴

이 있습니까? 가능한 한 일반적인 것을 유지하고 싶습니다. 아마도 추가 상태를 추가하고 기존 파트 주변에 모나드 코드를 추가해야 할 필요가 있기 때문입니다.

여기에 실현하기 위해 중요한 점은 당신이 ST을 사용하고 완전히 관련이없는을 점이다. ST 참조 자체는 다양한 장소에서 액세스해야하는 일반적인 값이지만 은 실제로을 변경하려고하지 않습니다. 변경 가능성은 ST에서 발생하지만 STRef 값과 그 외의 것들은 기본적으로 읽기 전용입니다. 이름은 이며 변경 가능한 데이터는입니다. 물론

, 주변 환경에 대한 읽기 전용 액세스는 Reader 모나드가 무엇인지입니다. 모든 함수에 대한 참조의 추악한 전달은 정확히 당신이하는 일이지만, 이미 ST에 있기 때문에 모나드 변환기로 사용하면됩니다. 당신이 abstract over the details of the reference types을 할 수 더 일반성을 위해

newtype STEnv s e a = STEnv (ReaderT e (ST s) a) 
    deriving (Functor, Applicative, Monad) 

runEnv :: STEnv s e a -> ST s e -> ST s a 
runEnv (STEnv r) e = runReaderT r =<< e 

readSTEnv :: (e -> STRef s a) -> STEnv s e a 
readSTEnv f = STEnv $ lift . readSTRef . f =<< ask 

writeSTEnv :: (e -> STRef s a) -> a -> STEnv s e() 
writeSTEnv f x = STEnv $ lift . flip writeSTRef x . f =<< ask 

및 모나드 일반적인 "가변 참조와 환경"으로합니다 간단한 예를 들어, 당신은 이런 식으로 뭔가를 할 수 있습니다.

+0

이것은 좋은 생각처럼 들리지만 참조가 실제로 변경되지 않는다는 사실을 잊어 버렸습니다. 고마워! 또한 자신의 숨겨진 로컬 상태로 액세스 할 필요가없는 상위 레벨 환경에서 실행되는 독립적 인 상태 계산을 분리하기 위해 ST 모나드 자체를 사용하는 것에 대해 궁금합니다. 이 경우 ST 모나드 변환기를 사용해야합니까, 아니면 ST 모나드 내부에 run = $ run을 사용할 수 있습니까? 만약 당신이 (변압기를 사용하지 않고) 당신이 둘러싸고있는 모나드로부터 심판을 역 참조하려한다면 (그들이 범위에 있다고 가정한다면) 어떻게 될 것입니까? – Tom

+0

@Tom : 'ST'에 대한 변압기가 없습니다. 'IO'처럼 항상 스택 하단에 있습니다. 게다가,'runST'에 대한 호출 내에서 일어나는 두 가지 완전한'ST' 계산은 서로의 상태와 완전히 분리되어 있으며, 그것들을 혼합하려고 시도하면 타입 오류가 발생합니다. ST 내부에서'IORef'를 전달할 수있는 것처럼 불투명 한 값을 전달할 수 있지만'IORef'를 사용할 수있는 것보다 * 사용할 수는 없습니다. 당신은'runST'를 평소처럼 사용할 수 있습니다. 그 결과는 언제나처럼 순수한 가치입니다. –

+0

@Tom : 만약 당신이 나의 예제처럼'ReaderT'를 사용한다면, 너무 많은 문제없이 여러 종류의 브라케팅 연산을 구현할 수 있습니다. - 현재 환경을 복제하여 내부의'ST'에서 실행하고, 다른 환경을 가진 같은 'ST'에서, & c. –

5

당신은 당신이 단지 배열과 심판 및 다른 IO의 케이크를 얻을 명심 단지 IO 모나드처럼 ST 모나드를 사용할 수 있습니다. IO와 마찬가지로, 계산을 통해 투명하게 일부 상태를 스레드하려는 경우 StateT를 그 위에 레이어 할 수 있습니다.

+0

오, 나는 그 생각을하지 못했다. 내 문제가 해결 될 것이라고 생각한다. – Tom

관련 문제