Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
pp:hoogle [2019/03/03 16:56] dmihai [Anatomia unui rezultat] |
pp:hoogle [2019/04/12 14:49] (current) dmihai [Căutare după tip] |
||
---|---|---|---|
Line 3: | Line 3: | ||
[[https://www.haskell.org/hoogle/|Hoogle]] este un motor de căutare pentru funcții, tipuri, clase etc. de Haskell. Puterea sa constă în abilitatea de a căuta funcții atât după nume cât și după tip. | [[https://www.haskell.org/hoogle/|Hoogle]] este un motor de căutare pentru funcții, tipuri, clase etc. de Haskell. Puterea sa constă în abilitatea de a căuta funcții atât după nume cât și după tip. | ||
- | ====== Căutare după nume ===== | + | ==== Căutare după nume ==== |
Considerați că tocmai ați auzit de funcția Haskell ''scanl'', dar nu știți ce face. Căutând numele pe Hoogle (https://www.haskell.org/hoogle/?hoogle=scanl) obțineți o listă de rezultate similare; observați că hoogle face matching parțial și vă găsește și funcții numite ''scanl1''. | Considerați că tocmai ați auzit de funcția Haskell ''scanl'', dar nu știți ce face. Căutând numele pe Hoogle (https://www.haskell.org/hoogle/?hoogle=scanl) obțineți o listă de rezultate similare; observați că hoogle face matching parțial și vă găsește și funcții numite ''scanl1''. | ||
Line 11: | Line 11: | ||
</note> | </note> | ||
- | ===== Anatomia unui rezultat ===== | + | ==== Anatomia unui rezultat ==== |
{{:pp:hoogle-scanl-result.png|}} | {{:pp:hoogle-scanl-result.png|}} | ||
Line 18: | Line 18: | ||
* pe prima linie este numele complet al funcției, urmat de tipul funcției | * pe prima linie este numele complet al funcției, urmat de tipul funcției | ||
* click pe numele sau pe tipul funcției vă va duce la descrierea completă a acesteia din cadrul pachetului în care e definită | * click pe numele sau pe tipul funcției vă va duce la descrierea completă a acesteia din cadrul pachetului în care e definită | ||
- | * următoarea linie (cu verde) conține o listă separată cu virgulă de forma "pachet modul-din-pachet" în care se găsește funcția (nu e necesar să înțelegeți bine noțiunile de "pachet" și de "modul"; vă veți uita în principal după funcții care conțin ''base Prelude'') | + | * următoarea linie (cu verde) conține o listă separată cu virgulă de forma "pachet modul-din-pachet" în care se găsește funcția (nu e necesar să înțelegeți bine noțiunile de "pachet" și de "modul"; cel mai des vă veți uita după funcții care conțin ''base Prelude'') |
* următoarea linie conține o descriere a comportamentului funcției; butonul ''+'' de la începutul rândului expandează acest câmp, dacă descrierea este lungă | * următoarea linie conține o descriere a comportamentului funcției; butonul ''+'' de la începutul rândului expandează acest câmp, dacă descrierea este lungă | ||
Line 32: | Line 32: | ||
<note tip> | <note tip> | ||
- | acumulatorul e 0; | + | întâi 0, acumulatorul\\ |
- | apoi 14, rezultatul operației (0 + 14); | + | apoi 14, rezultatul operației (0 + 14)\\ |
- | apoi 42, rezultatul operației (14 + 28); | + | apoi 42, rezultatul operației (14 + 28)\\ |
apoi 44, rezultatul operației (42 + 2) | apoi 44, rezultatul operației (42 + 2) | ||
+ | </note> | ||
+ | |||
+ | ==== Căutare după tip ==== | ||
+ | |||
+ | Când scrieți cod (indiferent de limbaj), veți ajunge des în situația în care aveți nevoie de un anumit comportament; vreți să găsiți o funcție despre care știți ce ați vrea să facă, însă nu știți cum s-ar putea numi. Ar fi util să existe o implementare pentru această funcție în biblioteca standard; astfel vă scutiți de timpul de dezvoltare a funcției și aveți garanția unei implementări robuste, testată de mulți. Hoogle vă ajută să o găsiți, dacă există. | ||
+ | |||
+ | === Exemplu === | ||
+ | |||
+ | Aveți de rezolvat următoarea problemă: se dă o listă de numere întregi; trebuie să o rearanjați astfel încât toate numerele pare să se afle la începutul listei, urmate de toate numerele impare. | ||
+ | |||
+ | <code> | ||
+ | [1, 2, 3, 4] -> [2, 4, 1, 3] | ||
+ | [44, 2, 13, 8, 77] -> [44, 2, 8, 13, 77] | ||
+ | [11, 1, 3, 9, 2] -> [2, 11, 1, 3, 9] | ||
+ | </code> | ||
+ | |||
+ | Pentru acest task, cel mai util ar fi să existe o funcție care face exact asta; din păcate aceasta nu se găsește în biblioteca standard Haskell. | ||
+ | Gândidu-ne la ce ne-ar fi de folos, putem ajunge la ideea că ne dorim o funcție care primește un predicat și o listă de întregi și ne întoarce un tuplu de două liste: elementele pentru care predicatul ține și restul. Funcția ar avea semnătura: | ||
+ | |||
+ | <code haskell> | ||
+ | (Int -> Bool) -> [Int] -> ([Int], [Int]) | ||
+ | </code> | ||
+ | |||
+ | Căutând acest tip pe hoogle, găsim 3 rezultate!\\ | ||
+ | https://www.haskell.org/hoogle/?hoogle=%28Int+-%3E+Bool%29+-%3E+%5BInt%5D+-%3E+%28%5BInt%5D%2C+%5BInt%5D%29 | ||
+ | |||
+ | Observăm că rezultatele nu au exact tipul dat de noi. Tipul la care ne-am gândit a fost mai restrictiv decât necesar, biblioteca standard oferindu-ne o soluție pentru liste de orice tip generic ''a''; hoogle a fost însă în stare să le găsească. | ||
+ | |||
+ | Dar ordinea parametrilor? Ce s-ar fi întâmplat dacă am fi căutat o funcție care primește întâi o listă, apoi predicatul?\\ | ||
+ | https://www.haskell.org/hoogle/?hoogle=%5BInt%5D+-%3E+%28Int+-%3E+Bool%29+-%3E+%28%5BInt%5D%2C+%5BInt%5D%29 | ||
+ | |||
+ | Aceleași rezultate! Hoogle reușește să găsească ce ne dorim chiar și în ciuda ordinii greșite a parametrilor. | ||
+ | |||
+ | Acum nu ne mai rămâne decât să citim descrierile funcțiilor găsite (''break'', ''span'', ''partition''). Observăm că ''partition'' are comportamentul dorit. Hoogle ne arată faptul că această funcție se află în modulul ''Data.List'', care trebuie importat: | ||
+ | |||
+ | <code> | ||
+ | Prelude> :m + Data.List | ||
+ | Prelude Data.List> partition even [1..10] | ||
+ | ([2,4,6,8,10],[1,3,5,7,9]) | ||
+ | Prelude Data.List> | ||
+ | </code> | ||
+ | |||
+ | Concatenând cele două liste, obținem soluția problemei inițiale: | ||
+ | |||
+ | <code haskell> | ||
+ | import Data.List | ||
+ | |||
+ | evensFirst l = let (e, o) = partition even l | ||
+ | in e ++ o | ||
+ | </code> | ||
+ | |||
+ | <note tip> | ||
+ | Am putea scrie o expresie mai scurtă, folosindu-ne de compunere de funcții? Funcția ''partition'' întoarce un tuplu, dar funcția de concatenare (''++'') primește pe rând două argumente - este curried. Putem rezolva problema, folosindu-ne de ''uncurry''. | ||
+ | |||
+ | |||
+ | <code haskell> | ||
+ | import Data.List | ||
+ | |||
+ | evensFirst = uncurry (++) . partition even | ||
+ | </code> | ||
+ | |||
+ | Funcția ''uncurry (++)'' are tipul ''([a], [a]) -%%>%% [a]''. | ||
</note> | </note> |