상용구 강의
우선, unsafePerformIO
척의 존재하지 않습니다. 둘째, 다음 번에는 좀 더 완전한 코드 스 니펫을 제시해주십시오. 결과적으로 가정을 통해 답변을 드리겠습니다.
워크 인을 통해
당신은 발표 :
gameLoop :: User -> IO()
gameLoop initUser = displayPosition initUser >> gameLoop (applyAction initUser)
그래서 당신이
displayPosition :: User -> IO()
에 대한 몇 가지 정의가 있어야합니다 보인다. 그런 다음
type UserAction = User -> User
인 것으로 보이는
UserAction
을 사용합니다.,
applyAction = maybe id (unsafePerformIO (fmap getUserAction getLine))
대신 마술 IO를 만들기 :
applyAction :: UserAction
이제 갑자기
User -> IO User
유형을 산출, 당신이
User -> User
유형을 원하지만 대신에 당신이하고 싶은이
IO
이 없습니다 실현 완전히 안전하지, 당신은 정의 할 수 없어 다음
gameLoop
로 돌아 간다
이
applyAction :: User -> IO User
applyAction previousUser =
do ln <- getLine
case getUserAction ln of
Nothing -> -- You never said what to do here.
-- This is the same logical issue as the missing
-- argument to your call to `maybe` above.
return previousUser -- XXX do something correct!
Just act -> return act
, 유형 변경 및 w 한 예 : 예상 값이 :: User
인 경우 applyAction initUser :: IO User
을 사용할 수 없습니다. 단순히
gameLoop initUser = displayPosition initUser >> applyAction initUser >>= \newUser -> gameLoop newUser
또는 :
gameLoop initUser = displayPosition initUser >> applyAction initUser >>= gameLoop
더 다시 쓰기
gameLoop initUser =
do displayPosition initUser
newUser <- applyAction initUser
gameLoop newUser
이가 단지 문법 설탕입니다 : 우리는, 그러나, 모나드 바인딩을 사용하거나 할-표기 할 수
그것은 하나의 해결책 이었지만 01을 유지하는 것이 좋습니다.함수는 효과가 없으므로 (IO가 없음) 테스트 할 수 있고 프로그램을 더 쉽게 리팩터링 할 수 있습니다. 루프를 작성하는 대신 루프를 작성하여 전달합니다.
gameLoop initUser =
do displayPosition initUser
command <- getLine
newUser <- applyAction command initUser
gameLoop newUser
applyAction :: String -> User -> User
applyAction cmd oldState = maybe oldState id (getUserAction ln)
'Control.Monad'에서 '영원히'볼 것을 제안합니다. –
동일한 모나드를 반복해서 실행하지 않습니까? 나는 initUser를 따라 가고 싶다. – hgiesel