[haskell] Hele vage error

Pagina: 1
Acties:

  • kvdveer
  • Registratie: November 2000
  • Laatst online: 06-11-2025
Ik moet sinds deze week Haskell leren voor mijn opleiding. Vol goede moed ben ik dus aan de slag gegaan.
De (aan mezelf gestelde) opdracht luidt:
Vind alle delers van een bepaald getal die kleiner of gelijk zijn dan de wortel van dat getal.
In opgave2.hs staat:
Haskell:
1
2
3
4
5
-- Is x een deler van y?
isDeler x y = (y `rem` x ) == 0

-- get alle delers < sqrt n
delers2 n = filter (`isDeler` n) [1..(truncate (sqrt n))]


Helaas levert dit een foutmelding op bij het uitvoeren:
code:
1
2
3
4
Main> delers2 1599
ERROR - Unresolved overloading
*** Type       : (Floating a, Integral a, RealFrac a) => [a]
*** Expression : delers2 1599

Als ik in de functie delers2 een van de twee N's vervang door een constante doet 'ie zijn werk wel.

Wat is hier fout aan?

(op google zoeken op Unresolved overloading + haskell levert me veel schijnbaar ongerelateerde hits op)
Ik gebruik Hugs voor windows, maar heb (zoals verwacht) dezelfde fouten op linux en cygwin.

Localhost, sweet localhost


  • oVRoM
  • Registratie: Juli 2000
  • Niet online
Je moet de functies ook typeren :) Anders pakt Hugs het niet!

  • kvdveer
  • Registratie: November 2000
  • Laatst online: 06-11-2025
oVRoM schreef op 04 november 2003 @ 17:57:
Je moet de functies ook typeren :) Anders pakt Hugs het niet!
Kun je me even een zetje in de goede richting geven? De functies die ik tot nu toe heb geschreven heb ik ook niet getypeerd (vermoed ik), maar die werkten wel.
We krijgen onze lesstof per week aangeleverd dus ik kan helaas niet vooruitbladeren.

Localhost, sweet localhost


  • oVRoM
  • Registratie: Juli 2000
  • Niet online
Je zult moeten aangeven wat het type is van de teruggeef waarde en de verwachte invoerwaarden. Dus Int, String, Char etc. En dan in de syntax TypeAgr1 -> TypeArg2 -> ReturnType

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 12:02

.oisyn

Moderator Devschuur®

Demotivational Speaker

Haskell ken ik niet, maar in Clean moest je altijd doen:

Clean:
1
2
isDeler :: a a -> a
isDeler x y = ...enz


En dat zorgde er dus voor dat isDeler op alle types werkt, zolang de 2 parameters maar gelijk aan elkaar zijn

Als je 'm alleen op ints wil laten werken moet je die a natuurlijk vervangen door Int

[ Voor 48% gewijzigd door .oisyn op 04-11-2003 18:13 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • oVRoM
  • Registratie: Juli 2000
  • Niet online
Dat is meer dan een aanzetje .oisyn :) Maargoed
Haskell:
1
2
isDeler :: Int -> Int -> Int
isDeler x y = uitwerking, eventueel met guards.

Verwijderd

Laten we het maar hier op houden:
(er moet trouwens een boolean uit komen (amateurs))
Haskell:
1
2
3
-- x is een deler van y 
isDeler :: Int -> Int -> Bool
isDeler x y = ((y `mod` x) == 0)

[ Voor 3% gewijzigd door Verwijderd op 04-11-2003 18:25 ]


  • oVRoM
  • Registratie: Juli 2000
  • Niet online
Hmmzz, klopt. Niet eten en internetten tegelijk dus in het vervolg :)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 12:02

.oisyn

Moderator Devschuur®

Demotivational Speaker

uiteraard ;)
Verwijderd schreef op 04 november 2003 @ 18:18:
(er moet trouwens een boolean uit komen (amateurs)
daar mist nog een haakje, prutser

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • oVRoM
  • Registratie: Juli 2000
  • Niet online
Verwijderd schreef op 04 november 2003 @ 18:18:
Laten we het maar hier op houden:
(er moet trouwens een boolean uit komen (amateurs))
Haskell:
1
2
3
-- x is een deler van y 
isDeler :: Int -> Int -> Bool
isDeler x y = ((y `mod` x) == 0)
Als we toch aan het mierenneuken zijn; die buitenste twee haakjes in je laatste regel zijn niet nodig :)
code:
1
isDeler x y = (y `mod` x) == 0

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 20-08 00:10
Ik zou trouwens zeggen dat die typedeclaratie niet vereist is; de compiler hoort dit juist uit te zoeken (leuke feature van functionele programmeertalen). Of is dat in Haskell niet zo?
oVRoM schreef op 04 november 2003 @ 18:26:
Als we toch aan het mierenneuken zijn; die buitenste twee haakjes in je laatste regel zijn niet nodig :)
code:
1
isDeler x y = (y `mod` x) == 0
Tja, dan zijn al die haakjes overbodig, aangezien functieapplicatie de hoogste prioriteit heeft:
Haskell:
1
isDeler x y = mod y x == 0

[ Voor 53% gewijzigd door Soultaker op 04-11-2003 18:31 ]


  • oVRoM
  • Registratie: Juli 2000
  • Niet online
Je hebt helemaal gelijk, vandaar dat op de tentamens erbij stond dat functie typering ook gewenst is ;)

  • Infinitive
  • Registratie: Maart 2001
  • Laatst online: 10-08 15:15
Het probleem is in dit geval ook niet de eerste functie. Het probleem zijn type-klasses en de boosdoener sqrt n.

code:
1
2
:t sqrt
sqrt :: forall a. (Floating a) => a -> a


Maar wat krijgt deze als parameter: juist iets wat een int zou moeten voorstellen. Of beter: een type uit de Num klasse, maar deze zit niet in de floating klasse.

Je zult je n parameter in dat gedeelte naar een floating-type moeten omzetten.

PS: in plaats van hugs moet je maar eens GHC proberen:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Loading package base ... linking ... done.
Compiling Test             ( test.hs, interpreted )
Ok, modules loaded: Test.
*Test> :t delers2
delers2 :: forall b.
           (Integral b, Floating b, RealFrac b) =>
           b -> [b]
*Test> delers2 10

Ambiguous type variable `b' in these top-level constraints:
  `Integral b' arising from use of `delers2' at <interactive>:1
  `RealFrac b' arising from use of `delers2' at <interactive>:1
  `Floating b' arising from use of `delers2' at <interactive>:1
*Test> :t isDeler
isDeler :: forall a. (Integral a) => a -> a -> Bool


Ik kon even niet zo snel vinden hoe ik ook al weer naar int toe ga i.p.v. integer ( :X ), maar als je de getallen met integers repressenteerd, dan werkt het volgende:

code:
1
2
3
4
5
6
7
8
-- Is x een deler van y?
isDeler x y = (y `rem` x ) == 0

-- get alle delers < sqrt n
delers2 n = filter (`isDeler` n) [1..truncate (sqrt (fromInteger n))]

*Test> delers2 10
[1,2]


En die laatste regel is wat lang. Misschien wel aardig om dat in een in of where block te gooien. Van het irritante haakjes afzetten kan je komen door de $-operator:

[1.. truncate $ sqrt $ fromInteger n]
Ik zou trouwens zeggen dat die typedeclaratie niet vereist is; de compiler hoort dit juist uit te zoeken (leuke feature van functionele programmeertalen). Of is dat in Haskell niet zo?
Typedeclaratie is niet vereist voor een groot deel van de functies. Er zijn echter een functies waarbij de type-inferencer niet krachtig genoeg voor is en het type alleen kan controleren.

Bovendien is het opsporen van fouten makkelijker als je zelf het een en ander aan types geeft. Het is leuk als je weet dat er 'ergens' een type-fout is, maar daar schiet je als gebruiker niet veel mee op.

[ Voor 69% gewijzigd door Infinitive op 05-11-2003 01:47 ]

putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]


  • Apollo_Futurae
  • Registratie: November 2000
  • Niet online
Infinitive schreef op 05 november 2003 @ 01:35:
code:
1
2
3
4
5
6
7
8
[...]
*Test> delers2 10

Ambiguous type variable `b' in these top-level constraints:
  `Integral b' arising from use of `delers2' at <interactive>:1
  `RealFrac b' arising from use of `delers2' at <interactive>:1
  `Floating b' arising from use of `delers2' at <interactive>:1
[...]
Dit kun je oplossen door
code:
1
delers2 (10 :: Integer)

of
code:
1
delers2 (10 :: Int)

Dit moet, omdat de compiler niet kan weten dat die twee gelijk zijn (dat is alleen in dit specifieke geval zo).
Ik kon even niet zo snel vinden hoe ik ook al weer naar int toe ga i.p.v. integer ( :X ), maar als je de getallen met integers repressenteerd, dan werkt het volgende:

code:
1
2
3
4
5
6
7
8
-- Is x een deler van y?
isDeler x y = (y `rem` x ) == 0

-- get alle delers < sqrt n
delers2 n = filter (`isDeler` n) [1..truncate (sqrt (fromInteger n))]

*Test> delers2 10
[1,2]
Beter lijkt me hier fromIntegral i.p.v. fromInteger, dat resulteert in het type
code:
1
delers2 :: forall b. (Integral b) => b -> [b]
Bovendien is het opsporen van fouten makkelijker als je zelf het een en ander aan types geeft. Het is leuk als je weet dat er 'ergens' een type-fout is, maar daar schiet je als gebruiker niet veel mee op.
Hier ben ik het volledig mee eens. Het is een goede gewoonte om elke top-level functie een typedeclaratie mee te geven.

Pas de replâtrage, la structure est pourrie.


  • Infinitive
  • Registratie: Maart 2001
  • Laatst online: 10-08 15:15
Is het de topic starter duidelijk wat de precieze oorzaak van het probleem is?

Aan de hand van het type van sqrt ziet de type-inferencer dat de parameter van delers2 van het floating-point-class type is. Verder komt de inferencer erachter dat deze parameter ook van het integer-class type is. De conclusie is dat de parameter van zowel het floating-point als integer-type moet zijn. Een geldige conclusie, maar er is alleen geen ingebouwd type dat een instantie is van beide classes (de rede mag duidelijk zijn), vandaar dat 'ie deze niet kan vinden.

Dit is een nadeel van type-classes. Wanneer je concrete typen zou hebben gebruikt:
code:
1
2
3
4
wortel = sqrt :: float -> float

deler2 :: Int -> [Int]
deler2 = ...


Dan zou de type-checker de code ook meteen foutrekenen, omdat een 'Int' niet te vereningen is met een 'float'. Het nadeel hier weer aan is dat je functies nu minder algemeen zijn.

[offtopic]
Wat betreft het 'hele vage error': Je zult er vast nog een heleboel meer krijgen. De meest vage error-melding die me bij gebleven is, is 'unification gives infinite type'. Toen ik dat voor het eerst zag wist ik niet wat ermee bedoeld wordt.

putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]

Pagina: 1