Iteraattori

Kokeneet kirjoittajat eivät ole vielä tarkistaneet sivun nykyistä versiota, ja se voi poiketa merkittävästi 4.5.2019 tarkistetusta versiosta . tarkastukset vaativat 10 muokkausta .

Iteraattori ( englanniksi  iterator - enumerator) on käyttöliittymä , joka tarjoaa pääsyn kokoelman elementteihin ( taulukko tai säilö ) ja navigoinnin niiden läpi [1] . Iteraattoreilla voi olla eri yleiset nimet eri järjestelmissä. Tietokannan hallintajärjestelmissä iteraattoreita kutsutaan kursoreiksi . Yksinkertaisimmassa tapauksessa matalan tason kielten iteraattori on osoitin .

Iteraattorien käyttö yleisessä ohjelmoinnissa mahdollistaa universaalien algoritmien toteuttamisen konttien kanssa työskentelemiseen [1] .

Kuvaus

Iteraattorien päätarkoitus on antaa käyttäjälle mahdollisuus päästä käsiksi mihin tahansa säilön elementtiin piilottaen samalla säilön sisäisen rakenteen käyttäjältä. Tämä sallii säiliön tallentaa elementtejä millä tahansa tavalla niin kauan kuin käyttäjä hyväksyy sen käsittelevän sitä yksinkertaisena sarjana tai luettelona . Iteraattoriluokan suunnittelu liittyy yleensä läheisesti vastaavaan konttiluokkaan. Tyypillisesti säilö tarjoaa menetelmiä iteraattorien luomiseen.

Iteraattori on perustoiminnoiltaan samanlainen kuin osoitin : se osoittaa objektikokoelman yksittäiseen elementtiin (tarjoaa pääsyn elementtiin ), ja se sisältää toimintoja, joilla siirrytään toiseen luettelon elementtiin (seuraavaan tai edelliseen). Säilön, joka toteuttaa iteraattoreiden tuen, tulee tarjota luettelon ensimmäinen elementti sekä mahdollisuus tarkistaa, onko säilön kaikkia elementtejä iteroitu (jos iteraattori on äärellinen). Käytetystä kielestä ja tarkoituksesta riippuen iteraattorit voivat tukea lisätoimintoja tai määrittää erilaisia ​​käyttäytymismalleja.

Joskus silmukkalaskuria kutsutaan "silmukkaiteraattoriksi". Silmukkalaskuri tarjoaa kuitenkin vain elementin iteroinnin, ei pääsyä elementtiin.

Erot indeksoinnista

Proseduuriohjelmointikielet käyttävät laajasti silmukkamäärään perustuvaa indeksointia iteroidakseen sekvenssin kaikkia elementtejä ( kuten taulukkoa ). Vaikka indeksointia voidaan käyttää yhdessä joidenkin oliopohjaisten säilöjen kanssa, iteraattorien käyttämisessä on etuja:

Kyky muokata säilöä sen elementtejä iteroitaessa on tullut välttämättömäksi nykyaikaisessa olio-ohjelmoinnissa , jossa objektien väliset suhteet ja toimintojen suorittamisen seuraukset eivät välttämättä ole liian ilmeisiä. Iteraattorin käyttö pääsee eroon tällaisista ongelmista.

Implisiittiset iteraattorit

Joillakin oliopohjaisilla kielillä, kuten Perl , Python , C# , Ruby ja Java- ja Delphi uusimmat versiot , on erikoisoperaattoreita konttielementtien iterointiin ilman iteraattoreita erikseen. Todellinen iteraattori voi todellakin olla olemassa, mutta jos se on olemassa, sitä ei ole erikseen ilmoitettu lähdekoodissa.

Iterointi kokoelman elementtien läpi käyttämällä implisiittistä iteraattoria tehdään käyttämällä " foreach " -lausetta (tai vastaavaa), kuten seuraavassa Python-koodissa:

arvolle luettelossa : tulosta arvo _ _

Muissa tapauksissa iteraattorit voidaan luoda itse objektien kokoelmalla, kuten tässä Ruby-esimerkissä:

lista . jokainen tekee | arvo | lopettaa arvon _

Listaa käyttävät kielet voivat myös käyttää implisiittisiä iteraattoreita luodessaan tuloksena olevaa luetteloa, kuten Python:

MaleNames = [ Henkilö . Henkilöluettelossa olevan henkilön nimi , jos henkilö . Ismies ]

Joskus implisiittisyys on vain osittaista. Esimerkiksi C++-kielen vakiomallikirjasto sisältää joitain funktiomalleja, jotka esimerkiksi suorittavat tällaisen implisiittisen iteroinnin. Ne vaativat kuitenkin edelleen eksplisiittisen iteraattorin parametrina. Mutta alustuksen jälkeen seuraava iteraatio tapahtuu implisiittisesti ilman iteraattoria. C++11 -standardin jälkeen kieli tukee myös implisiittistä silmukan iteraatiota [2] . for_each()for

Generaattorit

Yksi tapa toteuttaa iteraattorit on käyttää yhteisproseduureja , jotka voivat palauttaa ohjauksen (ja lasketut tulokset) useita kertoja muistaen niiden tilan ja paluupisteen edellisestä kutsusta. Joissakin kielissä yhteisproseduurit voidaan esittää erityisellä funktiolla , jota kutsutaan generaattoriksi . Generaattori on funktio, joka muistaa missä edellinen paluu oli, ja seuraavan kerran kun sitä kutsutaan, se jatkaa toimintaansa keskeytetystä paikasta.

Useimmat iteraattorit kuvataan luonnollisesti generaattoreina, ja koska generaattorit säilyttävät nykyisen tilansa kutsujen välillä, ne sopivat hyvin monimutkaisiin iteraattoreihin, joiden toteutus vaatii monimutkaisia ​​tietorakenteita muistaakseen nykyisen sijainnin kokoelmassa, kuten puun läpikulku .

Esimerkki generaattorista, joka palauttaa Fibonacci - luvut yieldPython - operaattorilla :

def fibonacci (): a , b = 0 , 1 , kun taas True : tuottaa a # return a, + muista mistä aloittaa seuraava kutsu a , b = b , a + b fibonaccin numerolle ( ): # Käytä generaattoria iteraattoritulostusnumerona

Iteraattorit eri ohjelmointikielillä

Oberon

Tavallinen viittaus sarjan muodostaviin muuttujiin tapahtuu niiden lukumäärän perusteella. Tässä tapauksessa vaaditun muuttujan osoite lasketaan seuraavasti: "1. muuttujan osoite" + "muuttujan koko" x "joukkonumero". Tällaisten muuttujien peräkkäisellä pääsyllä voit saada merkittävän suorituskyvyn lisäyksen, jos lasket seuraavan muuttujan osoitteen edellisen osoitteen kautta. Tätä varten liukusäädin on tarkoitettu. Muuttujien tyyppiä, jotka muodostavat sarjan, joihin päästään peräkkäin, kutsutaan liukusäätimen viitetyypiksi, ja sarjassa olevien muuttujien lukumäärää, jonka verran liukusäädin liikkuu jokaisen tällaisen käytön jälkeen, kutsutaan liukusäätimen askeleeksi. . Liukusäätimen askel on annettu kokonaislukuvakiona. Jos liukusäätimen askelta ei ole määritetty näkymää määritettäessä, askeleen katsotaan olevan yhtä suuri kuin 1.

C++

C++-kieli käyttää laajasti iteraattoreita STL :ssä , joka tukee useita erityyppisiä iteraattoreita, mukaan lukien "yksisuuntaiset iteraattorit", "kaksisuuntaiset iteraattorit" ja "satunnaispääsyiteraattorit". Kaikki vakiosäiliötyyppiset mallit toteuttavat vaihtelevan mutta johdonmukaisen iteraattorityypin joukon. Vakioiteraattorien syntaksi on tehty samankaltaiseksi kuin tavalliset C - kielen osoittimet , joissa ja -operaattoreita käytetään määrittämään elementti, johon iteraattori osoittaa, ja osoittimen aritmeettisia operaattoreita, kuten , käytetään siirtämään iteraattori seuraavaan elementtiin. *->++

Iteraattoreita käytetään yleensä pareittain, joista toista käytetään osoittamaan nykyinen iteraatio ja toista käytetään merkitsemään kokoelman loppua. Iteraattorit luodaan käyttämällä asianmukaisia ​​säilöluokkia vakiomenetelmillä, begin()kuten end(). Funktio begin()palauttaa osoittimen ensimmäiseen elementtiin ja palauttaa osoittimen viimeistä seuraavaan end() kuvitteelliseen olemattomaan elementtiin.

Kun iteraattori ohittaa viimeisen elementin, tämä on määritelmän mukaan yhtä suuri kuin iteraattorin erityinen loppuarvo. Seuraava esimerkki havainnollistaa iteraattorin tyypillistä käyttöä:

std :: lista < int > C ; // Mitä tahansa standardia STL-säilöä voidaan käyttää std::list:n sijaan for ( std :: list < int >:: iterator it = C . begin (), end = C . end (); it != end ; ++ it ) { //muuttuva iteraattori * it = 8 ; // iteraattorin osoittamaa elementtiä voidaan muuttaa } for ( std :: lista < int >:: const_iterator it = C . alkaa (), end = C . end (); it != end ; ++ it ) { //jos sinun ei tarvitse muokata elementtejä std :: cout << * it << std :: endl ; }

On olemassa monia erilaisia ​​iteraattoreita, jotka eroavat käyttäytymisestään: yksisuuntaiset, käänteiset (käänteiset) ja kaksisuuntaiset iteraattorit; syöttö- ja lähtöiteraattorit; const iteraattorit (suojaavat säilön tai sen elementtien muuttamiselta). Kaikki säilötyypit eivät kuitenkaan tue mitään näistä iteraattorityypeistä. Käyttäjät voivat luoda omia iteraattorityyppejä määrittelemällä alaluokkia standardin perusteella std::iterator.

Iteraattorin käytön turvallisuus määritellään erikseen erityyppisille vakiosäiliöille; joissakin tapauksissa iteraattori sallii säilön muutokset iteroinnin aikana.

C++ tukee osittain myös implisiittistä iteraatiota vakiofunktiomallien, kuten std::for_each()[1] ja std::accumulate()[2] , kautta . Käytettäessä ne on alustettava olemassa olevilla iteraattoreilla, tyypillisesti alussa ja lopussa , jotka määrittävät iteroinnin laajuuden, mutta iteraattoreille ei saa olla selkeää määritelmää lisäiteraatioita varten. Seuraava esimerkki havainnollistaa for_each.

ContainerType < ItemType > C ; // Mikä tahansa vakionimikesäiliötyyppi ItemType void ProcessItem ( const ItemType & I ) // Funktio, joka käsittelee jokaisen kokoelman kohteen { std :: cout << I << std :: endl ; } std :: for_each ( C.begin ( ) , C.end ( ), ProcessItem ) ; // View Loop

Tämän menetelmän haittapuoli on kyvyttömyys ilmoittaa silmukan runkoa sisällä, mikä vaatii jossain määrittämään funktioosoitin tai funktion ja välittämään sen argumenttina. Tämä voidaan osittain kompensoida käyttämällä Boostin kaltaista kirjastoa ja lambda-funktiota luomaan implisiittisesti funktioita, joilla on samanlainen infix-operaattorin syntaksi. Vain tämä mielessä tällaisen kirjaston on suoritettava tietyt toiminnot tietyillä tavoilla.

C++11 -standardista alkaen iteraattoreita voidaan käyttää implisiittisesti silmukassa for, mikä tarjoaa toiminnallisuuden iteroida kaikkia säilön elementtejä:

#sisällytä <vektori> #include <iostream> int main ( tyhjä ) { std :: vektori < int > v ; v . push_back ( 1 ); v . push_back ( 2 ); v . push_back ( 3 ); for ( auto e : v ) { std :: cout << e << std :: endl ; // Tulosta kunkin elementin arvo } paluu 0 ; }

Java

Java -kielen JDK 1.2 -julkaisussa esitelty käyttöliittymä java.util.Iterator tarjoaa säiliöluokkien iteroinnin. Jokainen Iteratortoteuttaa next()ja hasNext()tukee valinnaisesti remove(). Iteraattorit luodaan vastaavien konttiluokkien avulla, yleensä iterator().

Menetelmä next()siirtää iteraattorin seuraavaan arvoon ja palauttaa määritetyn arvon iteraattorille. Alun perin luotu iteraattori osoittaa erityiseen arvoon ennen ensimmäistä elementtiä, joten ensimmäinen elementti voidaan hakea vasta ensimmäisen kutsun jälkeen next(). Testimenetelmää käytetään määrittämään, milloin kaikki säiliön elementit on iteroitu hasNext(). Seuraava esimerkki havainnollistaa iteraattorien yksinkertaista käyttöä:

Iteraattori iter = lista . iteraattori (); //Iteraattori<MyType> iter = list.iterator(); J2SE 5.0:ssa while ( iter . hasNext ()) System . ulos . println ( iter.seuraava ( ) );

Tätä tukevien tyyppien kokoelmassa iteraattorimenetelmä remove()poistaa viimeksi vieraillun elementin säilöstä. Lähes kaikki muut säilön muokkaukset iteroinnin aikana eivät ole turvallisia.

Sillä java.util.Liston java.util.ListIteratormyös samanlainen API, mutta se mahdollistaa iteroinnin eteen- ja taaksepäin, mikä mahdollistaa luettelon nykyisen indeksin määrittämisen ja siirtymisen elementtiin sen sijainnin perusteella.

J2SE 5.0: n julkaisun myötä otettiin käyttöön käyttöliittymä Iterable, joka tukee parannettua foreachia kokoelmien ja taulukoiden iterointiin. määrittää menetelmän , joka palauttaa . Käyttämällä parannettua silmukkaa edellinen esimerkki voidaan kirjoittaa uudelleen muotoon forIterableiterator()Iteratorfor

for ( MyType obj : list ) System . ulos . tulostaa ( obj );

C# ja muut .NET-kielet

.NET Frameworkin iteraattoreita kutsutaan "luetteloilijoiksi" ja niitä edustaa IEnumerator. IEnumeratortoteuttaa menetelmän MoveNext(), joka siirtyy seuraavaan elementtiin ja osoittaa, onko kokoelman loppu saavutettu; ominaisuutta Currentkäytetään määritetyn elementin arvon saamiseksi; valinnainen menetelmä Reset()palauttaa luetteloijan alkuperäiseen paikkaansa. Luettelomies osoittaa aluksi erityistä arvoa ennen ensimmäistä elementtiä, joten kutsu MoveNext()on tarpeen iteroinnin aloittamiseksi.

Luettelijat välitetään yleensä kutsumalla menetelmää GetEnumerator()objektissa, joka toteuttaa IEnumerable. Säilöluokat toteuttavat tyypillisesti tämän rajapinnan. C# foreach -lauseke voi kuitenkin toimia missä tahansa objektissa, joka tukee tällaista menetelmää, vaikka se ei toteuttaisi . Molempia käyttöliittymiä on laajennettu .NET 2.0 :n yleisissä versioissa . IEnumerable

Seuraava esimerkki näyttää yksinkertaisen iteraattorien käytön C# 2.0:ssa:

// IEnumerator < MyType > iter = lista 'eksplisiittinen' versio . GetEnumerator (); while ( iter . MoveNext ()) Konsoli . WriteLine ( iter . Current ); // 'implisiittinen' versio foreachista ( MyType -arvo luettelossa ) Konsoli . WriteLine ( arvo );

C# 2.0 tukee myös generaattoreita : menetelmä, joka on ilmoitettu palautettavaksi IEnumerator(tai IEnumerable), mutta joka käyttää " " (flexible return) -lauseketta yield returnelementtijonon tuottamiseen objektien palauttamisen sijaan, kääntäjä muuttaa uudeksi luokkaksi, joka toteuttaa asianmukaisen käyttöliittymä.

Python

Pythonin iteraattorit ovat kiinteä osa kieltä, ja niitä käytetään monissa tapauksissa implisiittisesti lausekkeessa for( hakusilmukka ), luettelon käsittelyssä ja generaattorilausekkeissa . Kaikki Python-kieleen kuuluvat vakiosilmukkatyypit tukevat iteraatiota, samoin kuin monet luokat , jotka ovat osa . Seuraava esimerkki osoittaa tyypillisen implisiittisen iteroinnin silmukalla:

arvolle järjestyksessä : tulosta ( arvo ) _ _

Python-sanakirjoja (eräänlainen assosiatiivinen taulukko ) voidaan myös iteroida suoraan palauttaen sanakirjan avaimia. Tai sanakirjan kohteet -menetelmä voidaan toistaa, kun se täydentää liittyvän avaimen, ja tämän parin arvo on monikko:

avain sanakirjassa : arvo = sanakirja [ avain ] tulosta ( avain , arvo ) _ _ avaimelle arvo sanakirjassa . _ _ _ kohteet (): tulosta ( avain , arvo )

Iteraattoreita voidaan kuitenkin käyttää ja määritellä eksplisiittisesti. Sisäänrakennettu funktio iter()luo iteraattorin mille tahansa luetellulle silmukalle tai luokalle. Iteraattori toteuttaa menetelmän next(), joka palauttaa säilön seuraavan elementin. Kun elementtejä ei ole enää jäljellä, syntyy virheilmoitus StopIteration. Seuraava esimerkki havainnollistaa sopivan silmukan iteroinnin eksplisiittisiä iteraattoreita käyttäen:

it = iter ( sekvenssi ) ja True : try : value = it . seuraava ( ) paitsi StopIteration : break print ( arvo )

Seuraavassa esimerkissä Python 2.4:ssä (ja uudemmissa) iteraattori on itse tiedostoobjekti f, joka käyttää tiedostoa merkkijonosarjana:

f = open ( "README" ) # avaa tiedosto print ( f . next ()) # iteraattorin seuraava arvo on tiedoston seuraava rivi tulosteen ( summa ( len ( rivi ) riville f ) ) # the tiedoston kaikkien muiden rivien pituuksien summa

Mikä tahansa mukautettu luokka voi tukea standardiiteraatiota (eksplisiittistä tai implisiittistä) määriteltäessä menetelmää __iter__(), joka luo iteraattorin. Iteraattori tarvitsee sitten menetelmän määritelmän next(), joka palauttaa seuraavan elementin. On syytä ymmärtää ero iteroitavan objektin (objektin, josta funktio iter()palauttaa iteraattorin) ja iteraattorin (objektin, jolla on menetelmä __next__) välillä.

Python-kielen generaattorit toteuttavat tämän iteroinnin protokollan.

PHP

PHP 4 esitteli look-loop -rakenteet Perlissä ja joissakin muissa . Tämän avulla voit selata taulukoita yksinkertaisella tavalla. PHP 4:ssä hakusilmukka toimii vain taulukoiden kanssa ja antaa virheen, kun sitä yritetään käyttää erityyppisten muuttujien tai alustamattomien muuttujien kanssa.

PHP5:ssä hakusilmukka mahdollistaa objektien iteroinnin kaikkien julkisten jäsenten läpi.

Tätä varten on kaksi syntaksia, joista toinen on pieni mutta erittäin hyödyllinen laajennus ensimmäiselle.

Esimerkki A

<?php foreach ( array_expression muodossa $arvo ) echo " $arvo ; \n " ; ?>

Esimerkki B

<?php foreach ( array_expression as $key => $arvo ) echo "( $avain ) $arvo ; \n " ; ?>

Esimerkki A iteroi joukolle välitetyn taulukon array_expression. Joka kerta silmukan läpi nykyisen elementin arvo määritetään muuttujalle $value, ja sisäinen taulukon osoitin siirtyy seuraavaan elementtiin (joten silmukan seuraavassa iteraatiossa "näet" seuraavan elementin).

Esimerkki B osoittaa samanlaisen toiminnallisuuden kuin yllä on esitetty. Mutta täydentää sitä sillä tosiasialla, että nykyisen elementin avainarvo (tässä tapauksessa array_expression) osoitetaan muuttujalle $keysilmukan jokaisella kierrolla.

PHP mahdollistaa taulukon sisällön muuttamisen iteroinnin aikana, jolloin riittää, että määritetään, että $value-arvo saadaan viitteeksi (PHP-termein), eli &$-arvona.

<?php $arr = array ( 1 , 2 , 3 , 4 , 5 ); foreach ( $arr as & $value ) $arvo ++ ; // lisää jokaista arvoa yhdellä // nyt $arr sisältää arvot: 2,3,4,5,6 ?>

PHP 5:ssä käyttöliittymä Iteratoron ennalta määritetty ja objekteja voidaan muokata iteroinnin ohjaamiseksi.

<?php class MyIterator toteuttaa Iteratorin { yksityinen $var = array (); julkinen funktio __konstrukti ( $taulukko ) { if ( is_array ( $array )) { $this -> var = $taulukko ; } } public function rewind () { echo " rewind \n " ; reset ( $this -> var ); } public function current () { $var = nykyinen ( $this -> var ); echo "current: $var\n " ; palauttaa $var ; } julkinen funktionäppäin () { $var = avain ( $this -> var ) ; echo "avain: $var\n " ; palauttaa $var ; } public function next () { $var = next ( $this -> var ); echo "seuraava: $var\n " ; palauttaa $var ; } julkinen funktio kelvollinen () { $var = $this -> current () !== false ; echo "oikein: { $var } \n " ; palauttaa $var ; } } ?>

Näitä menetelmiä hyödynnetään täysimääräisesti koko selaussyklin aikana foreach($obj AS $key=>$value). Iteraattorimenetelmät suoritetaan seuraavassa järjestyksessä:

1.rewind() ("siirtyminen") 2. kun voimassa() { 2.1 current() arvossa $ 2.3 key() $keyssä 2.4 seuraava() }

Edellinen esimerkki voidaan yksinkertaistaa huomattavasti käyttämällä IteratorAggregate-käyttöliittymää, joka pakottaa kehittäjän toteuttamaan vain yhden getIterator()-menetelmän.

<?php class MyIterator toteuttaa IteratorAggregate { yksityinen $var = array (); public function __construct ( array $array ) { // tyyppitarkistuksen tekee tulkki: __construct(array $array) $this -> var = $array ; } public function getIterator () { return new ArrayIterator ( $this -> var ); } } ?>

XL

Iteraattorit XL -kielessä ovat generaattoreiden ja iteraattorien yleistys.

tuonti IO = XL . ui . KONSOLI iteraattori IntegerIterator ( var out Laskuri : kokonaisluku ; alhainen , korkea : kokonaisluku ) kirjoitettu laskuri matalassa .. Korkea on laskuri : = alhainen kun laskuri <= korkea silmukan tuotto Laskuri += 1 // Huomaa, että erillistä I:n ilmoitusta ei tarvita, koska 'var out' on ilmoitettu iteraattorissa // I:n implisiittinen ilmoitus kokonaislukuna tapahtuu alla I in 1 .. 5 -silmukalle IO . Kirjoita " I = " , I

ActionScript1.0 (Flash)

for ( i = 0 ; i < taulukko . pituus ; i ++ ) { trace ( taulukko [ i ]); }

ActionScript 3.0(Flash/Flex)

ActionScript 3 :n iteraattorit on rakennettu itse kieleen, ja niitä tukevat foreach and for...in -lauseet . Kielen näkökulmasta dynaamisten luokkien taulukot ja esiintymät ovat iteraattoreita:

var obj : Objekti = { prop1 : "a" , prop2 : "b" , prop3 : "c" }; // seuraava silmukka "ajaa" kaikkien obj-objektin avainten (ominaisuuksien nimet) läpi for ( var name : String in obj ) trace ( nimi ); // seuraava silmukka "ajaa" kaikkien ominaisuusarvojen läpi obj foreach ( var val :* in obj ) trace ( val ); }

Haskell

Haskellin standardikirjasto määrittelee Traversable-tyyppiluokan [3] [4] :

luokka ( Funktori t , Taitettava t ) => Läpikulkukelpoinen t jossa poikki :: Applikatiivinen f => ( a -> f b ) -> t a -> f ( t b )

Tässä t  on jokin polymorfinen tyyppi (ehkä säiliö tai kokoelma ), f  on "showy"-tyyppi (esim. I/O, eksplisiittinen tilan muutos tai virheen mahdollisuus). "traverse" on functorin ja foldin erikoisala , joka ilmaistaan ​​luokan kontekstissa (otsikossa).

Esimerkiksi binääripuulle "traverse"-menetelmä voitaisiin määrittää seuraavasti:

tietopuu a = Tyhjä | _ lehti a | Solmu ( Puu a ) a ( Puu a ) instanssi Läpikäytettävä Puu poikki f Tyhjä = puhdas Tyhjä poikkisuunta f ( Lehti x ) = Lehti <$> f x poikki f ( Solmu l k r ) = Solmu <$> poikki f l <*> f k <*> poikki f r

Käyttöesimerkki:

-- | Tulosta kunkin puusolmun sisältö. printTree tree = poikki tulostuspuu _ -- | Tämä funktio ottaa jonkin binäärifunktion g ja puun, kulkee puun läpi soveltaen g:tä jokaiseen solmuun (toinen argumentti -- pyydetään vakiosyötteestä) ja palauttaa muokatun puun. yhdistäStdinin kanssa :: ( Lue c ) => ( a -> c -> b ) -> Puu ​​a -> IO ( Puu b ) yhdistäStdinin kanssa g = poikki yhdistä missä yhdistä x = g x <$> readLn {- Esimerkki: puu = Solmu (Solmu (Leaf 3) 6 (Leaf 9)) 10 (Solmu (Leaf 9) 0 Tyhjä) $ yhdistäStdin (+) -puun kanssa > 10 > 20 > 30 > 40 > 50 > 60 $ Solmu (Solmu (Leaf 13) 26 (Leaf 39)) 50 (Solmu (Leaf 59) 60 Tyhjä) -}

"Traversable"-tyyppiluokan menetelmien perusteella voit rakentaa omia funktioita tietyllä läpikulkustrategialla.

GHC - kääntäjän versiosta 6.12 lähtien "-XDeriveFunctor" "-XDeriveFoldable"- ja "-XDeriveTraversable"-laajennukset on otettu käyttöön automaattisesti luomaan sopivia tyyppiluokkia. Esimerkki:

tietopuu a = Tyhjä | _ lehti a | Solmu ( Puu a ) a ( Puu a ) johtaminen ( Funktori , Taitettava , Läpikulkuinen )

Katso myös

Muistiinpanot

  1. 1 2 Salter, Kleper, 2006 .
  2. ↑ Aluepohjainen silmukalle (alkaen C++11) -  cppreference.com . en.cppreference.com. Haettu 23. joulukuuta 2018. Arkistoitu alkuperäisestä 5. tammikuuta 2019.
  3. Data.Traversable . Haettu 13. heinäkuuta 2010. Arkistoitu alkuperäisestä 19. kesäkuuta 2010.
  4. Iteraattorimallin olemus . Käyttöpäivä: 13. heinäkuuta 2010. Arkistoitu alkuperäisestä 2. syyskuuta 2007.

Linkit

Kirjallisuus

  • Nicholas A. Salter, Scott J. Kleper. C++ ammattilaisille = Professional C++. - Dialectics, Williams, 2006. - S. 637-639. — 912 s. — ISBN 5-8459-1065-X .