2011-06-11 5 views

답변

1

State 모나드와 맞춤 수정 자 및 접근자를 결합했을 수 있습니까?

+0

역시 나에게'State' 모나드의 특정 사용하는 것 같습니다. –

-3

나는 상태 패턴에 대해 순수한 기능적 등가물이 있다고 생각하지 않습니다. 순수한 함수형 프로그래밍에는 상태와 시간의 개념이 없기 때문에. 상태 패턴은 본질적으로 상태와 시간에 관한 것입니다. 그러나 비 순수한 기능적 동등 물이 존재한다고 생각합니다. 그것은 무한한 게으른 평가 스트림입니다. C# yield로 구현할 수 있습니다.

+1

FP에는 실제로 상태가 있습니다. 모나드에 대해 들어 본 적이 없습니까? 시변 상태를 포착하기 위해 기능적 반응 형 프로그래밍이라고하는 것조차 있습니다. – fuz

+0

참고 "순수"와 "비 순수"라는 단어를 사용합니다. – Dagang

+1

"기능 프로그래밍"과 "상태"를 연결하는 데 올바른 단어가 있다고 생각하지 않습니다. 저는 그것을 "모델"이라고 생각합니다. 우리는 국가의 기능적 모델을 구축함으로써 상태 계산을 할 수 있습니다. – luqui

7

이 패턴은 State monad을 사용하는 예이며 계산식 환경은 상태가있는 코드를 보강합니다.

다음은 하스켈에서 구현 한 것입니다.

일부 헬퍼 : 프로그램

data Mode = A | B 

카운터로 보강이 모드 상태 연산의 종류의 동작

import Control.Monad.Trans.State 
import Control.Monad.IO.Class 
import Data.Char 

두 모드. A 국

을 초기에 상태 저장 연산을 실행,

writeName :: String -> StateM() 
writeName s = do 
    (n,mode) <- get 
    case mode of 
     A -> do liftIO (putStrLn (map toLower s)) 
       put (0,B) 
     B -> do let n' = n + 1 
       liftIO (putStrLn (map toUpper s)) 
       if n' > 1 then put (n', A) 
          else put (n', B) 

실행 프로그램 :

type StateM a = StateT (Int, Mode) IO a 

write 함수의 StateM 컨텍스트 기능은 는 상태 모드에 기초하여 동작을 변경

main = flip runStateT (0, A) $ do 
    writeName "Monday" 
    writeName "Tuesday" 
    writeName "Wednesday" 
    writeName "Thursday" 
    writeName "Saturday" 
    writeName "Sunday" 

위의 코드에서 메인의 출력은 다음과 같습니다.

monday 
TUESDAY 
WEDNESDAY 
thursday 
SATURDAY 
SUNDAY 

참고 :이 기능은 순수한 기능 솔루션입니다. 이 프로그램에는 변경 가능하거나 파괴적인 업데이트가 없습니다. 대신, 상태 모나드는 계산을 통해 원하는 모드를 스레드합니다.

+1

이것이 충실한 인코딩이라고는 말할 수 없습니다. 여기에서는 모든 모드를 한 곳 ('데이터 모드 ')으로 선언해야하며 위키 백과 예제에서는 선언을 모듈 식으로 결합 할 수 있습니다. – luqui

+0

ML 스타일의 닫힌 데이터 타입에 대한 표준 번역입니다. 분명히 우리는 함수 나 타입 클래스를 통해 열린 데이터 타입을 사용할 수 없지만이 문제와 관련이 없다고 생각합니다. –

+1

표준 번역본이 무엇인지 궁금하다. – luqui

5

한 인코딩 :

import Data.Char (toUpper, toLower) 

newtype State = State { unState :: String -> IO State } 

stateA :: State 
stateA = State $ \name -> do 
    putStrLn (map toLower name) 
    return stateB 

stateB :: State 
stateB = go 2 
    where 
    go 0 = stateA 
    go n = State $ \name -> do 
       putStrLn (map toUpper name) 
       return $ go (n-1) 

IO에 속지 마십시오,이 그 패턴의 순수한 번역이다 (우리는 국가 또는 아무것도를 저장하기 위해 IORef를 사용하지 않는). newtype 확장, 우리는이 타입이 무엇을 의미하는지 참조 : 등,

State = String -> IO (String -> IO (String -> IO (String -> ... 

그것은 문자열을 사용합니다 일부 I/O를 수행하고 다른 문자열을 요청

이 추상 클래스 패턴의 내가 가장 좋아하는 인코딩입니다 OO : 추상 클래스 -> 타입, 서브 클래스 -> 그 타입의 요소.

newtype State 선언은 추상 writeName 선언 및 서명 대신 사용됩니다. StateContext을 새 상태로 지정하는 대신 새 상태를 반환하면됩니다.IO에 반환 값을 포함하면 새 상태가 I/O에 의존하도록 허용됩니다. 즉,이 예에서 기술적 필요가 없기 때문에, 우리는 여전히 계산을 표현할 수있는 더욱 엄격한 타입

newtype State = State { unState :: String -> (State, IO()) } 

를 사용할 수 있지만, 상태의 순서는 고정 된 입력에 의존 할 수 없다. 그러나 원래의 더 관대 한 유형을 고집합시다.

그리고 "테스트 클라이언트"에 대한

: 합의

runState :: State -> [String] -> IO() 
runState s [] = return() 
runState s (x:xs) = do 
    s' <- unState s x 
    runState s' xs 

testClientState :: IO() 
testClientState = runState stateA 
        [ "Monday" 
        , "Tuesday" 
        , "Wednesday" 
        , "Thursday" 
        , "Saturday" 
        , "Sunday" ] 
+0

P. 카운터 토글 링 의미를 캡처해야합니다. –

+0

@Don, 오, 맞아. 흠 .... – luqui

+0

가치있는 것을 위해,이 인코딩 스타일은 추상화 된 동작을 캡슐화하는 실제 OO 관용적 클래스에만 이상적이라고 말하고 싶습니다. 혐의로 OO 코드에서 우울한 수의 "클래스"는 사용 된 스타일의 서투른 번역에 훨씬 가깝기 때문에 처음에 원하는 것을 다시 사용하게됩니다. –

관련 문제