2016-07-22 30 views
4

Ich habe die folgende Funktion, um die Faktor-Paare für eine bestimmte AnzahlMehrdeutige Typ Variable `a0' die sich aus einer Verwendung von` es

factorPairs:: (RealFrac a, Floating a, Integral a) => a -> [(a, a)] 
factorPairs n = map(\x -> (x, div n x)) [y | y <- [1..(ceiling $ sqrt n)], n `rem` y == 0] 

zurückzukehren Wenn ich die Funktion in GHCI nennen factorPairs 18 Ich erhalte ein Laufzeitfehler von

* Ambiguous type variable `a0' arising from a use of `it' 
     prevents the constraint `(Floating a0)' from being solved. 
     Probable fix: use a type annotation to specify what `a0' should be. 
     These potential instances exist: 
     instance Floating Double -- Defined in `GHC.Float' 
     instance Floating Float -- Defined in `GHC.Float' 
    * In the first argument of `print', namely `it' 
     In a stmt of an interactive GHCi command: print it 

ich die Funktion in GHCI hart codieren können

map(\x -> (x, div 18 x)) [y | y <- [1..(ceiling $ sqrt 18)], 18 `rem` y == 0] und haben keine Probleme, aber ich kann nicht scheinen, um herauszufinden, warum meine Funktion fehlschlägt. Ich glaube, dass Ghci versucht, mir zu sagen, dass es nicht herausfinden kann, welcher Typ print mit anrufen soll, aber ich kämpfe, um die Lösung zu finden.

+0

Try „: t Karte (\ x -> (x, div 18 x)) [y | y <- [1 .. (Decke $ sqrt 18)], 18' rem' y == 0 ] "auf GHCi, um den abgeleiteten Typ herauszufinden. – Mephy

+1

Sie sollten Ihre Typ-Signatur überdenken. Können Sie einen Typ angeben, der sowohl "Floating" als auch "Integral" ist? Ich schlage vor, dass Sie die Funktion monomorph machen, ex "Double" verwenden und nur bei Bedarf verallgemeinern. –

+0

@ ThomasM.DuBuisson Ich habe darüber eigentlich zum Spaß nachgedacht: Gibt es jemals einen _reasonable_ Typ, der sowohl 'Floating' als auch' Integral' ist? Gibt es auch eine Möglichkeit, auf der Basis von Instanzen nach Arten zu suchen, wie wir mit hoogle oder hayoo nach Funktionen auf der Basis von Typen suchen können? – Alec

Antwort

5

Dies hat damit zu tun, dass numerische Literale in Haskell überlastet sind. Wenn Sie map(\x -> (x, div 18 x)) [y | y <- [1..(ceiling $ sqrt 18)], 18 `rem` y == 0] in ghci eingeben, ist das 18, das ein Argument zu sqrt ist, standardmäßig zu Double und die anderen zu Integer s.

Wenn Sie jedoch

factorPairs:: (RealFrac a, Floating a, Integral a) => a -> [(a, a)] 
factorPairs n = map(\x -> (x, div n x)) [y | y <- [1..(ceiling $ sqrt n)], n `rem` y == 0] 

Sie alle Instanzen von n zwingen schreiben nur eine Art zu haben. Dann wird das Problem, dass es einfach keine Standard-Zahlentypen gibt (eigentlich überhaupt Zahlentypen, denke ich), die alle diese Einschränkungen erfüllen, daher sagt GHC Ihnen von "möglichen Instanzen", die es versucht. Die Lösung ist fromIntegral hinzuzufügen und die Beschränkungen zu lockern:

factorPairs:: Integral a => a -> [(a, a)] 
factorPairs n = map(\x -> (x, div n x)) [y | y <- [1..(ceiling $ sqrt $ fromIntegral n)], n `rem` y == 0] 
4

Eine weitere Möglichkeit des Typs Fehler loszuwerden, ist die Verwendung von sqrt zu beseitigen. Da Haskell faul ist, können Sie einfach über [1..n] iterieren und anhalten, wenn Ihr Teiler größer als Ihr Quotient ist.

factorPairs :: Integral a => a -> [(a, a)] 
factorPairs n = takeWhile (uncurry (>=)) [ (n `div` d, d) | d <- [1..n], n `mod` d == 0] 

uncurry (>=) ist nur eine andere Art \(q, d) -> q >= d zu schreiben. Wenn Sie dies in monadischer Form schreiben, können Sie divMod verwenden, um den Quotienten und den Rest mit einer einzigen Funktion zu erhalten.

factorPairs n = takeWhile (uncurry (>=)) $ do 
       d <- [1..n] 
       let (q, r) = n `divMod` d 
       guard $ r == 0 
       return (q, d)