2012-06-06 2 views
2

C 및 Java 배경에서 하스켈을 처음 사용했습니다. 때때로, 나는 하스켈의 타입 시스템에 문제가있다. 나의 현재 오류가이 코드 조각입니다 :let 바인딩의 모호한 유형 변수

countIf :: (Integral b) => [a] -> (a -> Bool) -> b 
countIf [] p = 0 
countIf (x:xs) p 
    | p x = 1 + countIf xs p 
    | otherwise = countIf xs p 

isRelativelyPrime :: (Integral a) => a -> a -> Bool 
isRelativelyPrime m n = gcd m n == 1 

phi :: (Integral a, Integral b) => a -> b 
phi n = countIf [1..(n - 1)] (isRelativelyPrime n) 

main = print [(n, phi n, ratio) | n <- [1..10], let ratio = (fromIntegral (phi n))/n] 

오류 메시지가

prog.hs:13:60: 
    Ambiguous type variable `b' in the constraints: 
     `Fractional b' arising from a use of `/' at prog.hs:13:60-85 
     `Integral b' arising from a use of `phi' at prog.hs:13:75-79 
    Probable fix: add a type signature that fixes these type variable(s) 

13:60 그냥 메인에 내 지능형리스트에 바인딩하자에 fromIntegral의 사용 전입니다. ghc의 오류 메시지에 익숙해 지려고합니다. 컴파일 할 코드를 변경하기 위해 필요한 것을 알아 내기 위해이 특정 코드를 해독 할 수 없습니다. 어떤 도움이라도 대단히 감사하겠습니다. 감사.

+2

'countIf'는 표준 함수의 조합으로 정의 될 수 있습니다 :'countIf = length. 플립 필터 '. – demi

답변

3

Haskell은 Integral (phi n)에서 호출 한 이후 이미 알고있는 정수 유형을 자동으로 변환하지 않으므로 n에 대해 Integral을 호출해야합니다. 나는 항상이 실수를한다. 큰 문제가 아니다!

+0

감사합니다. 그게 제가 놓친 세부 사항입니다. –

6

이것은 일반적인 초보자 실수의 예입니다. 지나치게 다형성 코드입니다.

코드를 최대한 일반화했습니다.

phi :: (Integral a, Integral b) => a -> b 

이것은 phi 변환을 통해, 다른 일체형으로 임의 일체형 걸릴 것이다.

이러한 다형성 코드는 라이브러리에 적합하지만 유형 유추에는 적합하지 않습니다. 난 그냥이 정수에 작업 할 돈을 넣어 것, 그래서 우리는 가서는 A보다 정확한 유형을 제공,

countIf :: [Integer] -> (Integer -> Bool) -> Integer 
countIf [] p = 0 
countIf (x:xs) p 
    | p x  = 1 + countIf xs p 
    | otherwise = countIf xs p 

isRelativelyPrime :: Integer -> Integer -> Bool 
isRelativelyPrime m n = gcd m n == 1 

phi :: Integer -> Integer 
phi n = countIf [1..(n - 1)] (isRelativelyPrime n) 

main = print [ (n, phi n, ratio) 
      | n <- [1..10], let ratio = (fromIntegral (phi n)) ] 

및 유형의 오류가 바로 사라질 수 있습니다.

성능이 향상 될 수도 있습니다 (특히 Int을 전문으로하는 경우).

+0

나는 개인적으로 초심자에게 Int를 추천하는 것에 반대하지만, 과도한 다형성을 문제로 인식하기 위해 +1한다. –

+0

@DonStewart 과도한 다형성에 대한 조언을 주셔서 감사합니다. 나는 아마이 시점에서 그걸 가지고 배 밖으로 나갈 것입니다. 그러나 오류가 그 변경 사항으로 사라지지 않습니다. 귀하의 코드에는 오류 메시지가 발생한 "let ratio = ..."바인딩 (따라서 이름 "비율")의 구분이 없습니다. 위의 Max의 대답은 부동 소수점 나누기를 수행하기 위해 "fromInteger n"이 필요했기 때문에 오류를 해결했습니다. –

+0

@benmachine 왜 초보자 용으로 Int를 추천하지 않습니까? –