2011-09-09 8 views
0

제약 조건의 모호한 유형 변수 'a1'이 경우를 다음과 같이 생각할 수 있습니다. 응용 프로그램이 동적으로 모듈을로드하거나 사용자가 선택하는 함수 목록이 있습니다. 우리는 특정 유형이 해당 모듈의 기능과 함께 성공적으로 작동하는지 여부를 결정하는 메커니즘을 가지고 있습니다. 이제 우리는 그 함수를 호출하려고합니다. 우리는 전화를 걸도록 강요해야합니다. 이 함수는 구체적인 유형 또는 다형성을 취할 수 있으며 그 유형에 따라 문제가있는 유형 클래스 제약 조건이 아래에 있습니다.이 컴파일 오류를 해결하는 방법은 무엇입니까?

다음 코드는 아래 오류를 발생시킵니다. 구체적인 유형을 지정하여 해결할 수 있다고 생각하지만 그렇게하고 싶지는 않습니다. 이 코드는 클래스의 인스턴스 인 모든 유형에서 작동하도록 만들어졌습니다. 구체적인 유형을 지정하면 그 목적을 무효화합니다.

이것은 다른 프로그램에 대해 모르는 프로그램의 한 부분을 시뮬레이트하고 처리 대상의 유형을 모릅니다. 나는 유형이 적절하게 일치하는지, 실제로 전송 된 값이 유형 클래스의 인스턴스인지를 확인하는 별도의 메커니즘을 가지고있다. 그래서이 경우 unsafeCoerce를 사용해도 상관 없습니다. 하지만 기본적으로 컴파일러에게 내가 정말로 확인한다는 것을 알 수있는 방법이 필요합니다. 어쨌든 형식 검사를하기에 충분하지 않더라도 그렇게 할 수 있습니다. doTest2

[1 of 1] Compiling Main    (Test.hs, Test.o) 

Test.hs:12:3: 
    Ambiguous type variable `a1' in the constraint: 
     (HasString a1) arising from a use of `test' 
    Probable fix: add a type signature that fixes these type variable(s) 
    In the expression: test 
    In the expression: test $ unsafeCoerce h 
    In an equation for `doTest1': 
     doTest1 [email protected](Hider h) = test $ unsafeCoerce h 
실행 doTest1

[1 of 1] Compiling Main    (Test.hs, Test.o) 

Test.hs:12:3: 
    Ambiguous type variable `a1' in the constraint: 
     (HasString a1) arising from a use of `test' 
    Probable fix: add a type signature that fixes these type variable(s) 
    In the expression: test 
    In the expression: test $ unsafeCoerce h 
    In an equation for `doTest1': 
     doTest1 [email protected](Hider h) = test $ unsafeCoerce h 

실행

{-# LANGUAGE ExistentialQuantification, RankNTypes, TypeSynonymInstances #-} 
module Main where 

import Unsafe.Coerce 

main = do 
    --doTest1 $ Hider "blue" 
    doTest2 $ Hider "blue" 

doTest1 :: Hider -> IO() 
doTest1 [email protected](Hider h) = 
    test $ unsafeCoerce h 

doTest2 :: Hider -> IO() 
doTest2 [email protected](Hider h) = 
    test2 hh 

test :: HasString a => a -> IO() 
test x = print $ toString x 

test2 :: Hider -> IO() 
test2 (Hider x) = print $ toString (unsafeCoerce x) 

data Hider = forall a. Hider a 

class HasString a where 
    toString :: a -> String 

instance HasString String where 
    toString = id 

+0

답변은 다음과 같습니다. 할 수 없습니다. 따라서, 나는 내가하고 싶은 일을하는 법을 묻는 새로운 질문을 시작할 것이고, 내가 취하는 접근 방식과는 다른 방식으로 그것을 할 수 있기를 희망한다. – mentics

답변

2

I think it could be resolved by specifying concrete types but I do not want to do that.

unsafeCoerce으로하지만 주위 방법은 없습니다. 이 특별한 경우에는 test이 여전히 다형성이므로 컴파일러는 unsafeCoerce 유형을 유추 할 수 없습니다. HasString의 인스턴스가 하나만 있긴하지만 유형 시스템은 그 사실을 사용하여 유형을 추론하지 않습니다.

이 패턴의 특정 응용 프로그램에 대한 정보가 충분하지 않지만, 프로그램에서 유형 시스템을 사용하는 방식을 다시 생각해 봐야한다는 점을 확실히 알고 있습니다. 그러나 실제로 이것을 원할 경우 unsafeCoerce 대신 Data.Typeable을 조사하는 것이 좋습니다.

+0

그리고 실제로 HasString의 인스턴스가 하나만 존재할 필요는 없습니다.나는 당신이 Data.Typeable로 제안하는 것을 이해하지 못한다. – mentics

+0

그럼 '이론적으로'unsafeCoerce h '유형을 구체적으로 추측하는 것은 불가능합니다. 맞습니까? ;)'Data.Typeable'에 대해서 : 나는 그것을 직접 사용한 적이 없지만, 당신이하고 싶은 것처럼 보이는 동적 캐스팅에 도움이된다는 것을 이해했다. –

+0

아, 죄송합니다. 'Data.Dynamic'은 다이내믹 타이핑을하며, Typable을 사용하여 다이내믹 타이핑을합니다. 그것을 읽을 수 있습니다 :) –

1

약간 데이터 형식을 수정

data Hider = forall a. HasString a => Hider a 

가 명백한 방법으로 형 클래스의 인스턴스 확인 :

instance HasString Hider where 
    toString (Hider x) = toString x 

다음이 작동합니다, unsafeCoerce를 사용하지 않고 :

doTest3 :: Hider -> IO() 
doTest3 hh = print $ toString hh 

이것은 더 이상 값을에 배치 할 수 없음을 의미합니다.에 HasString이 구현되어 있지 않다면 좋겠지 만 그게 좋습니다.

아마도이 패턴의 이름이 있지만, 내 머리 꼭대기에있는 것이 무엇인지 생각할 수 없습니다.

+0

죄송합니다. 저에게 적합하지 않습니다. 이것은 지나치게 단순한 예입니다. 완전한 것이면, Hider에 무엇이든 들어있을 수 있습니다. – mentics

+1

@taotree하지만 HasString 타입을 HasString 타입으로 강요하려고합니다 - 하스켈이 피하도록 설계된 segfaults와 같은 문제를 필연적으로 일으킬 것입니다. "unsafeCoerce"의 "안전하지 않은"은 실제로 "안전하다는 자신의 증명을하지 않고서는 이것을 사용하는 것이 안전하지 않습니다"를 의미하며 안전하다는 증거가 있다고 말합니다. 이러지 마. –

+0

나는 그것이 안전하지 않다는 증거가 어디에서 나왔습니까? 나는 그것이 안전하다는 것을 증명했다고 말한 줄 알았다. – mentics

관련 문제