2017-11-14 9 views
2

, 나는 여기에하스켈 임의 typeclass 인스턴스 반환 형식

quickCheck (semigroupAssoc :: IdentAssoc) 

로 호출,

semigroupAssoc :: (Eq m, S.Semigroup m) => m -> m -> m -> Bool 
semigroupAssoc a b c = 
    (a S.<> (b S.<> c)) == ((a S.<> b) S.<> c) 

type IdentAssoc = Identity String -> Identity String -> Identity String -> Bool 

의 임의 typeclass 인스턴스

instance (Arbitrary a) => Arbitrary (Identity a) where 
    arbitrary = do 
     a <- Test.QuickCheck.arbitrary 
     return (Identity a) 
을 quickcheck 테스트를한다 쓰고 있어요

제 질문은 제 임의의 인스턴스에서 (Identity a) 또는 그냥 a를 반환 할 수 있다는 것입니다. (Identity a)는 정확하지만 컴파일러 오류가없고 실행시 무한 루프가 발생합니다. 왜 이런거야?

+0

동일한 기능을 다시 호출하기 만하면됩니다. –

+0

다시 부르는 함수는 무엇입니까? – tesserakt

+0

방금 ​​정의한 방. –

답변

4

유형 유추는 arbitrary 호출이 같음 인스턴스가 지금 정의하고있는 인스턴스를 변경하여 무한 루프가 발생합니다.

instance (Arbitrary a) => Arbitrary (Identity a) where 
    arbitrary = do 
     x <- Test.QuickCheck.arbitrary -- this calls arbitrary @ a 
     return (Identity x) 

instance (Arbitrary a) => Arbitrary (Identity a) where 
    arbitrary = do 
     x <- Test.QuickCheck.arbitrary -- this calls arbitrary @ (Identity a) 
     return x 

클래스 메소드를 호출 할 때마다 컴파일러는 호출 할 인스턴스를 추론합니다.

앞의 경우 컴파일러는 x :: a을 유추합니다 (이 유형 만 코드 유형을 확인합니다!) 따라서 arbitrary @ a을 호출합니다.

후자의 경우 컴파일러는 x :: Identity a을 유추합니다 (이 유형 만 코드 유형을 확인합니다!) 따라서 arbitrary @ (Identity a)을 호출하여 무한 루프가 발생합니다. 당신이로 작성하는 경우

+0

우수, 내 앞에 바로 있었다; 도와 주셔서 감사합니다. – tesserakt

+0

반환 형식을 변경하지 않습니까? 왜 컴파일러는 그것을 잡을 수 없었을까요? – tesserakt

+0

@tesserakt 내 마지막 편집이 이것을 분명히 밝히기를 바랍니다. – chi

4

:

instance Arbitrary a => Arbitrary (Identity a) where 
    arbitrary = do 
     x <- arbitrary 
     return x

(나는 덜 혼란을 야기 할 x- a 개명).

하스켈은 타입 배관을 할 것이고, return x이라고 쓰면, xIdentity a이어야합니다. 그리고 우리가 방금 정의한 것 (여기에서 굵게 표시)은 arbitrary :: Arbitrary a => Gen a이 존재하기 때문에 운이 좋습니다.

그래서 우리는 무한 루프를 구성했다는 것을 의미합니다.

public int foo(int x) { 
    return foo(x); 
} 

은 물론 우리가 이러한 기능을 정의 할 수 있습니다, 우리는 유형을 확인하는 경우가 올바른지 : 자바 예를 들어, 그것과 같을 것이다.

instance Arbitrary a => Arbitrary (Identity a) where 
    arbitrary = do 
     x <- arbitrary 
     return Identity x

하스켈이 있음을 유도 할 것이다 : 우리가 다시 다시 다시 그 기능을 호출 할 것 같은 함수를 호출 유지하지만 이후

당신은 그러나 작성하는 경우 ... 물론 어떤 진행이 xa 유형입니다. 그리고 우리는 Arbitrary a이 보유해야한다고 정의했기 때문에 다시 운이 좋았습니다. arbitrary :: Arbitrary a => Gen a 어딘가에 있지만, 다른 하나입니다. (그래서 내가 여기에 굵은 글씨로 쓰지 않았습니다.) 그 값을 생성 할 것입니다. Identity 생성자를 래핑합니다.첫 번째 예제에서, 우리는 심지어하지 않아도

참고는 Arbitrary a 제약를 추가합니다 : 참 :

instance Arbitrary (Identity a) where 
    arbitrary = do 
     x <- arbitrary 
     return x

이 잘 컴파일, 우리는 임의의 a을 생성하지 때문이다.