2013-03-19 2 views
2

previous question에서 모나드 코드를 알아 내려고 노력했습니다.하스켈 "추론 할 수 없다", "타입 변수가 아닌 인수"

import Control.Monad 
import Control.Monad.Error 

newtype FSM m = FSM { unFSM :: String -> m (String, FSM m) } 

fsm f []  = return [] 
fsm f (r:rs) = do 
    (xs, f') <- unFSM f r 
    liftM (xs:) (fsm f' rs) 

지금이 잘 컴파일 : 여기에, 시작하려면 상태 시스템 내가 사용 기능입니다

exclaim :: (Monad m) => FSM m 
exclaim = FSM exclaim' 
exclaim' xs = return (xs ++ "!", exclaim) 

하지만이 때문에 유형 선언하지 않습니다 :

question :: (MonadError String m) => FSM m 
question = FSM question' 
question' xs 
    | last xs == '?' = throwError "Already a question" 
    | otherwise  = return (xs ++ "?", question) 

오류는 Non type-variable argument입니다. 이는 이후에 String을 나타냅니다. 형식 선언을 제거하면 대신 Could not deduce이 표시됩니다. 나는 FlexibleContext를 활성화하는 것이이 문제를 "고칠 수있다"는 것을 이해하고 있지만 오류를 던지기 위해 할 수있는 간단한 방법이 있습니까? 차라리 모든 종류의 컴파일러 확장을 활성화하지는 않을 것입니다.

전체 코드 here. 당신이 절대적으로 FlexibleContexts 또는 NoMonomorphismRestriction를 사용하지 않을 경우

+5

'FlexibleContexts'는 아주 해가없는 확장입니다. 그 것을 두려워 할 필요가 없습니다. 형식 서명이 없으면 monomorphism 제한을 사용하지 않으면 컴파일됩니다. –

+1

확장 기능이 필요하지 않은 경우에는 약간 불리한 점이 있습니다. 차라리 코드를 재구성하는 대안적인 접근법을 찾고 싶습니다. 솔루션 1은 FlexibleContext입니다. 다른 제안? – me2

+0

더 많거나 적다면 얻을 수있는 모든 솔루션은 "FlexibleContexts를 켜십시오". " 확장 프로그램을 두려워하지 마라. 그들은 당신을 도울 것이다. 그리고 이것은 신비하지 않습니다. 구체적으로 당신이하고 싶은 것을 정확하게 할 수 있도록하는 것입니다. 아무것도 더, 아무것도 덜. – Carl

답변

4

, 당신은 당신의 모듈에 확장 켜지 않고도 questionquestion' 조금이라도 더 일반적으로는 컴파일 할 수 있습니다 :

question :: (Error e, MonadError e m) => FSM m 
question = FSM question' 

question' :: (Error e, MonadError e m) => String -> m (String, FSM m) 
question' xs 
    | last xs == '?' = throwError $ strMsg "Already a question" 
    | otherwise  = return (xs ++ "?", question) 

그것을 던져 확인 strMsg을 사용하여 일반 Error 유형을 입력하고 유형 서명을 지정하십시오.

그래도 FlexibleContexts을 사용하는 것이 좋습니다.

4

Daniel의 대답을 자세히 설명하려면 실제로 그의 해결책은 FlexibleContexts을 피하는 일반적인 해결책입니다.

이 같은 제약 조건이 모든 시간 : SomeTypeFlexibleInstances 경고를 전달 몇 가지 구체적인 유형입니다

(SomeTypeConstructor SomeType) => ... 

을 ..., 당신은 항상 당신이 사용하고자하는 타입 클래스라는으로 작업을 주위 FlexibleContexts을 사용할 수 있습니다 당신의 제약에 다음

class IsSomeType t where 
    get :: t -> SomeType 
    set :: SomeType -> t -> t 

... 그리고 통합 IsSomeType : 같은 SomeType,

(IsSomeType t, SomeTypeConstructor t) => ... 

... IsSomeType의 메소드 만 사용하십시오.