ul-fmf / projekt-tomo

Spletna storitev za poučevanje programiranja
https://www.projekt-tomo.si
GNU Affero General Public License v3.0
14 stars 23 forks source link

`Check.equal` ne dela pravilno #149

Closed andrejbauer closed 7 years ago

andrejbauer commented 7 years ago

V kodi, ki preverja pravilnost rezultatov, vidimo, da to naredi z Check.clean(rezulat) == Check.clean(pricakovani_rezultat). Funkcija Check.clean izračuna kanonično obliko vrednosti, vendar pozabi njen tip. Zato bo Check.equal mislil, da sta [('a',1), ('b',2)] in {'a':1, 'b':2} enaki vrednosti.

Rešitev: Check.clean(x) naj vedno doda še tip rezultata, torej vrača urejeni par (t, c) kjer je t enak type(x) in je c kanonična predstavitev x.

matijapretnar commented 7 years ago

Kaj pa vem, če je to pametno. Potem 1 ne bi bil pravilen odgovor za funkcijo, ki pričakuje 1.0, kar se zgodi precej pogosto. Zadeva je lahko še bolj zapletena, saj se uporablja pri Check.secret.

jaanos commented 7 years ago

Kaj pa, če bi se za numerične tipe privzeto naredila izjema? Pa še vedno se lahko doda parameter, če naj se preverjajo tipi (True: vedno, False: nikoli, None: samo nenumerični tipi).

matijapretnar commented 7 years ago

Potem predlagam tole: doda se funkcija, npr. Check.typed_clean, ki vrne tudi tip. Check.clean potem samo vzame prvo komponento in je privzeta izbira, tako kot do sedaj. Kdor želi imeti tudi tipe, bo moral v svojih testih napisati (…, clean=Check.typed_clean).

strelec commented 7 years ago

Rešitev s tipom pa bo rekla, da sta [[('a',1), ('b',2)]] in [{'a':1, 'b':2}] enaka. Ker boste verjetno beležili samo tip na čisto zgornjem nivoju.

Kaj pa če enostavno pimerjate toString reprezentacijo?

matijapretnar commented 7 years ago

Nisem sicer pognal #151, vendar se mi zdi, da je zadeva rekurzivna, zato imajo tipe tudi vsi podizrazi.

jaanos commented 7 years ago

Tako je:

>>> from check import *
>>> x = [[('a',1), ('b',2)]]
>>> y = [{'a':1, 'b':2}]
>>> Check.clean(x)
(<class 'list'>, [(<class 'list'>, [(<class 'tuple'>, ((<class 'str'>, 'a'), (<class 'int'>, 1))), (<class 'tuple'>, ((<class 'str'>, 'b'), (<class 'int'>, 2)))])])
>>> Check.clean(y)
(<class 'list'>, [(<class 'dict'>, [((<class 'str'>, 'a'), (<class 'int'>, 1)), ((<class 'str'>, 'b'), (<class 'int'>, 2))])])
>>> 

Mimogrede, zgornje je možno šele z zadnjim commitom, sicer check.py ni bilo mogoče uvoziti kot takega.

matijapretnar commented 7 years ago

Zdaj sem v #151 dodal to, da je tip, neobvezno in privzeto izklopljeno. S tem je zadeva kompatibilna za nazaj in primerna za večino primerov. Kdor želi tipe, lahko pri svojih testih piše Check.equal(…, clean=lambda x: Check.clean(x, typed=True)) in podobno za ostale funkcije iz Check, ki podpirajo clean. @andrejbauer, se ti zdi to v redu?

Zdaj lahko naprej razglabljamo, ali bi stvari bolj zapletali, da bi lahko pisali Check.equal(…, clean=Check.clean(typed=True)) ali pa kar Check.equal(…, typed=True). Ena možnost je, da vse funkcije iz Check svoj **kwargs posredujejo naprej v Check.clean.