2014-10-07 3 views
3

나는 이러한 기능에서 찾아 봤는데 :왜이 두 haskell 함수는 동등하지 않습니까?

import Data.Digits (digits) 
numberDivider (a,b) = a/b 
numberDivider2 (num,denom) = num/denom 
           where 
           a = head $ digits 10 num 
           b = head . tail $ digits 10 denom 

우리는 이러한 기능의 유형을 볼 수 있습니다 :

λ> :t numberDivider2 
numberDivider2 :: (Integral a, Fractional a) => (a, a) -> a 
λ> :t numberDivider 
numberDivider :: Fractional a => (a, a) -> a 

numberDivider 당신이 그것을 수행 생각하는 것이 무엇 않습니다. numberDivider2 준다 : 올바른 인수라고

No instance for (Show a0) arising from a use of ‘print’ 
The type variable ‘a0’ is ambiguous 
Note: there are several potential instances: 
    instance Show Double -- Defined in ‘GHC.Float’ 
    instance Show Float -- Defined in ‘GHC.Float’ 
    instance (Integral a, Show a) => Show (GHC.Real.Ratio a) 
    -- Defined in ‘GHC.Real’ 
    ...plus 34 others 
In a stmt of an interactive GHCi command: print it 

(예컨대 (48,98)). 이제 더 구체적인 것을 만드는 것이 모호함을 가져 오는 것을 어떻게 볼 수 있습니까? 나는 어리 석다는 생각이 든다. 함수가 I가이 Integral이며, b는 플로트 또는 무언가 곳이 (a,a) -> b 될 것이라고 생각하는 것처럼 (a,a) -> a에서 이동해야하는 이유 (I도 볼 수 없습니다.

을 내가 그것을 강제로 유형 약어에 퍼팅 시도 결과에 대한 플로트를 사용합니다.

사람이 내가 여기에 누락 무엇을 지적 할 수 있습니까? 이것은 아마 내가 추측하고있어 digits의 정의에서 오는

+0

전체 코드를 제공 할 수 있습니까? 예를 들어, 인쇄 할 호출이없고 예를 들어 여기에서 'digits'을 볼 수 있습니다 : http://hackage.haskell.org/package/digits? – Carsten

+0

답이 패키지보다'digits' 인 경우 대답은이 함수가 추가 제약 조건을 필요로한다는 것입니다. http://hackage.haskell.org/package/digits-0.2/docs/Data-Digits.html – Carsten

+0

문제는'print'로 당신은 구체적인 타입을 제약해야합니다 :'numberDivider (49,98) :: Float' 그러나 우리가 시도 할 수있는 완전한 코드 없이는 말하기가 어렵습니다 – Carsten

답변

6

가 인수 중 하나로서 Integrala => a 걸립니다.이를 그런 다음 인수에 Integral의 추가 제한 조건을 numberDivider2에 배치합니다. 여기에 FractionalIntegral의 인스턴스 인 유형은 없습니다. 그러나 숫자 리터럴을 입력하면 Num a => a에서 (Integral a, Fractional a) => a으로 변환하려고 시도하고 GHCi에서는 Show을 사용하는 인스턴스를 찾으려고하는 특수 규칙이 있으므로 화면에 인쇄 할 수 있습니다. 그러한 유형이 없기 때문에 오류가 발생합니다.

이제 실제 문제는 하스켈의 넘버 시스템에 대한 오해에서 비롯된 것 같습니다. Int과 같이 /을 모든 숫자에 사용할 수 없습니다. /이 해당 유형에 정의되어 있지 않기 때문입니다. 분수 유형에만 /을 사용할 수 있으므로 Fractional typeclass입니다. 부동 소수점 나누기를 수행하기 위해 Int 또는 IntegerFloat 또는 Double으로 변환하려면 fromIntegral을 사용하여 Num 유형 으로 변환 할 수 있습니다.

a = head $ digits 10 $ fromIntegral num 
b = head . tail $ digits 10 $ fromIntegral denom 

이렇게하면 함수에서 제약 조건 인 Integral이 제거되어야합니다. digits의 유형을보고 한 후


, 나는이 작동하지 않습니다 것을 알 수있다. 대신, 당신은 아마 당신이 Fractional 작업을 수행 할 위치

numberDivider2 :: (Integral a, Fractional b) => (a, a) -> b 
numberDivider2 (num, denom) = fromIntegral num/fromIntegral denom 
    where 
     a = head $ digits 10 num 
     b = head . tail $ digits 10 denom 

참고 fromIntegral의 위치 같은, 그들은이 시점에서 각 Integral 값을 변환 할 수 있습니다.

+0

좋은 답변 - 슬프게도 나는 오늘 내 업보트를 모두 낭비했다. ("vox populi"를 원했다.) – Carsten

+0

브릴리언트, 감사합니다. 숫자 유형과 당신은 그것을 완벽하게 설명했습니다. –

+1

@ CarstenKönig 하하, 괜찮습니다. 저는 질문에 대답하고 사람들이 반드시 배우를 얻을 필요가 없도록 돕기 위해 왔습니다. 나에게 잘못을 말하지 마라, 담당자는 재미있는 게임이다. 그러나 나는 벌써 20 k를 쳤다. 그리고 나는 더 이상 특권을 얻지 않는다. 그리고 나 자신은 Jon Skeet와 그의 대략의 평판 인 390278319874928473598791238480를 비교하면서 나쁘다고 느낀다. . – bheklilr

4

이제 더 구체적인 것을 만드는 것이 모호함을 초래하는 방법을 알지 못합니까?

두 경우 모두 모호하지만, numberDivider의 경우 모호성은 하스켈의 기본 규칙을 사용하여 해결할 수 있습니다. 이 특정 인스턴스에서 이러한 규칙은 기본적으로 여러 숫자 유형이 가능하고 그 중 하나가 Integer 인 경우 Integer을 선택한다고 말합니다. Integer이 가능하지 않지만 Double 인 경우 Double을 선택하십시오. 둘 다 불가능한 경우 모호성이 남아 있습니다. IntegerFractional는 인스턴스 아니지만 Double이므로 numberDividerInteger 경우

불가능하다. 따라서 Double이 선택됩니다.

numberDivider의 경우는 단순히 IntegralFractional 인 유형이 없으므로 어느 것도 가능하지 않습니다. 그러므로 모호함이 남아 있습니다.

정확하게 0 가능한 유형 집합이 모호하지 않지만 단순히 불가능하므로 오류 메시지가 달라야하지만 다른 곳에서 정의 될 수있는 인스턴스도 고려해야한다고 주장 할 수 있습니다. 즉, 표준 라이브러리에는 FractionalIntegral의 유형이 없지만 다른 유형으로 정의 될 수 있으므로 제외시킬 수는 없습니다 (의미가 없더라도).

+0

감사합니다. –

관련 문제