1)
Alla on python-funktio summation
, joka voi suorittaa kuutioiden / neliöiden summan / .., vastaavia operaatioita .
def identity(k): return k def cube(k): return pow(k, 3) def square(k): return pow(k,2) def summation(n, term): if n == 0: return 0 else: return term(n) + summation(n-1, term) def sum_cubes(n): return summation(n, cube) if __name__ == "__main__": sum = sum_cubes(4) print(sum) """ In C, We can implement the same using function pointers. Goal is, to perform similar operations(Sum of ..) using single function summation()"""
2)
Harkitse alla olevan sovelluksen lajittelua C: stä
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
Täällä qsort
voi lajitella minkä tahansa tyyppisiä tietoja , taulukossa olevien kelluvien tiedostojen / tiedostojen nimet / merkkijonot / …
Kysymys:
Kuinka määritetään yleinen funktio?
Onko summation
yleinen toiminto?
vai
Onko qsort
yleinen toiminto?
tai
Annetaan kaksi esimerkkiä, onko Yleinen funktio virheellinen terminologia?
Huomaa: Motivaatio-termi qsort
tai mikä tahansa suunnittelema toiminto
Kommentit
- Mikä on ” yleinen toiminto ” oletko lukenut, ettet ymmärrä ’? On hyödyllistä, jos lähetät sen sen sijaan, että kirjoittaisit joukon koodia.
- Tyyppiteorian termi sellaiselle yleiselle sanalle, jossa funktio toimii mille tahansa tyypille ilman rajoituksia ja tietämättä tiettyä tyyppiä, on parametrinen polymorfismi . Identiteettifunktio on yleinen tällä tavalla.
- Joillakin kielillä (kuten Java) ” geneerinen funktio ” on erityinen tekninen määritelmä. Mutta näin ei ole Pythonissa, joten ” yleisfunktiolla ” ei ole tarkkaan määriteltyä merkitystä. Se ei tarkoita, että se on ” virheellinen terminologia ”, vaan että sinun tulisi olla tietoinen asiayhteydestä käyttäessäsi termiä.
- @AndresF. Javascrpt käyttää myös tätä yleistä toimintoa terminologiaa. Koska sinulla voi olla toiminto, joka vie minkä tahansa html-elementin käsittelemään (esimerkki – poista kaikki annetun HTML-elementin lapset)
Vastaa
” Yleisillä ”on useita merkityksiä.
Epävirallinen määritelmä
”yleinen” jokapäiväisessä kielessä jotain, jolla on yhteisiä ominaisuuksia, mutta jollain tavalla vähemmän erityistä.
Tässä perspektiivissä voit harkita qsort()
yleisenä: tämän funktion koodi pystyy lajittelemaan minkä tahansa kiinteäkokoisen tietorakenteen, jolle voit määrittää vertailutoiminnon QSORT-algoritmilla.
Sama koskee summation()
-funktiotasi, joka sisältää yhteenvedon kaikista funktioista saadut termit yhdellä parametrilla.
Muodollinen määritelmä
Ohjelmointikielet, kuten C ++ tai Java, mahdollistavat yleisen ohjelmoinnin mallien tai yleisten ominaisuuksien avulla:
Määritelmä C ++ 14 -standardista : Malli määrittelee luokka- tai toimintoperheen tai aliaksen tyyppiperheelle.
Periaatteena on, että luokan tai funktion toteutus voidaan parametrisoida tyyppeittäin.
Tämän muodollisemman näkökulman mukaan qsort()
ei ole yleinen toiminto. Sen toteuttamisen ei tarvitse määrittää mitään tyyppiä käännöksessä, ja sen käyttäytyminen on tyypistä riippumatonta. Ainoa asia, jota se tarvitsee, on lajiteltavien elementtien koko, ja tämä koko on tavallinen argumentti, joka käsitellään ajon aikana.
kielelle, jota ei ole kirjoitettu staattisesti, kuten Python , en ole varma, mihin vastaamaan summation()
. Mielestäni se ei ole yleinen, koska sen toteutus ja käyttäytyminen eivät ole tyypistä riippuvaisia: tämä funktio on vain korkeamman tason funktio, argumentin term
ollessa Se ei käytä mitään ominaisuutta, joka muuttaisi funktion käyttäytymistä tyyppien perusteella.
Yleiskuvauksen havainnollistamiseksi voit tarkastella C ++ -funktiota std::sort()
: sen toteutus riippuu sen argumenttien tyypistä (ja valinnaisesti vertailutoiminto määrätyn tyyppisten argumenttien kanssa). Käyttämällä C ++ -mallien ominaisuuksia se voi lajitella minkä tahansa tyyppisen kontin sillä ehdolla, että sillä on operaattorit / jäsenfunktiot / piirteet / iteraattorit, joita tarvitaan yleisen toiminnon toteuttamiseksi.
Voiko dynaamisella kirjoitetulla kielellä olla yleisiä toimintoja
Dynaamisesti kirjoitettu kieli vaatii vähemmän yleistä koodia kuin staattisesti kirjoitetut kielet.
Jos sinulla on esimerkiksi dynaamisen tyyppisiä esineitä sisältävä säilö, qsort-toiminto voi lajitella säiliön yleisesti, kunhan säilössä olevien kahden elementin yhdistelmää voidaan verrata.
Mutta myös tällaisessa joustavassa ympäristössä yleinen – tyypistä riippuvainen – ohjelmointi voi olla hyödyllistä. Tyypillinen käyttötapaus on monimenetelmä, jossa käyttäytyminen tai koodi riippuu argumenttien tyypistä tai jopa tyyppien yhdistelmästä (esimerkiksi kahden eri muodon leikkauspisteen määrittämiseksi). Lisätietoja:
- Pythonin yleinen ohjelmointipaketti: multidispatch
- Yleisten toimintojen käyttäminen smalltalk-sovelluksessa
- Esimerkki yleisistä toiminnoista Common Lispissä
Kommentit
- Ei varma, miksi vertaamme yleisiä aineita (lähinnä käytetään välttämään Java-tyyppien suoratoistoa (katso -määrittely tai -opetusohjelma ). Siitä huolimatta olen ’ muokannut määritelmäosaa hieman huomautuksesi korjaamiseksi.
- Pythonin Generic-paketilla ei ole mitään tekemistä yleisten toimintojen kanssa. Paitsi että heillä on sama adjektiivi.
- @Killian, jos yleinen ohjelmointi , koskee ajatusta abstraktista konkreettisista, tehokkaista algoritmeista. yleisten algoritmien saamiseksi, jotka voidaan yhdistää erilaisiin dataesityksiin , mielestäni kyseisen paketin monimenetelmien tulisi olla, Don ’ t luuletko niin?
Vastaus
Yleiset funktiot ottavat vähintään yhden funktion argumentin tyypin yleisesti käännösaikana. Toisin sanoen kääntäjä selvittää, mitä tyyppiä käytetään tietyssä paikassa ja soveltaa juuri tätä tyyppiä, jos sitä käytetään toiminnossa. Esimerkiksi. jos funktiossasi on yleinen argumentti, jota käytetään +
-operaattorin kanssa, tyypillä on oltava asianmukaiset menetelmät. Merkkijonojen / taulukoiden kohdalla tämä olisi monessa tapauksessa ketjutus ja kokonaisluku / kelluva lisäys. Kääntäjä voi havaita, että sovellus käyttää oikeaa toimintaa. C-rutiini ei ole siinä mielessä yleinen, koska se on ohjelmoija, joka käyttää joitain kokotietoja eikä kääntäjä tunnista tyyppiä ja käyttää oikeaa kokoa.
Esim. Joillakin kuvitteellisilla kielillä
func add(p1,p2) { return p1+p2 } print add("a", "b") // yields "ab" print add(1, 2) // yields 3
Tässä kääntäjä havaitsee ensimmäisessä tapauksessa, että kahta merkkijonoa käytetään ja laajentaa sisäisesti jotain sellaista
func add(p1:string, p2:string)
ja käsittele +
ketjutuksena, kun taas toisessa tapauksessa se laajenee
func add(p1:int, p2:int)
toimitetun mukaisesti kokonaislukuparametrit. Yleinen tarkoittaa, että kääntäjä luo yksilöllisen koodin kääntöajan aikana. Esimerkiksi Python on kirjoittamaton ja tekisi tällaisen korvauksen ajon aikana. Tarkoitus: Pythonilla ei ole yleisiä toimintoja, koska kaikki on tavallaan yleistä.
Kommentit
- En saanut ideaasi. Tarkoitatko + on yleinen funktio, syntaksia C ++: ssa?
- Funktioita ottavat funktion argumentit ovat korkeamman asteen toiminto s Python / JavaScript-maailmassa. C: ssä tarvitsemme toiminto-osoittimia.
- Katso edellinen muokkaus.
- Millainen funktio on
summation
, Korkeamman tilauksen toiminto? eikä mitään muuta kuin se? - On olemassa paljon määritelmiä siitä, mikä geneerinen on. Stroustrup esimerkiksi määrittelee sen ” -ohjelmoinniksi käyttämällä tyyppejä parametreina ”. Wikipedia-viitteeksi, menen mieluummin osoitteeseen: fi.wikipedia.org/wiki/Generic_programming
Vastaus
Aloitan tämän C ++: n näkökulmasta ja jatkan sitten tietäni C. / p>
Staattisesti kirjoitetuilla kielillä, kuten C, C ++, Java jne., ”yleinen” -toiminto antaa sinun määrittää funktiotoiminnot kerran käyttämällä paikkamerkkejä kaikentyyppisille, jotka voivat vaihdella eri puhelujen välillä (mikä tarkoittaa toimintoja, kuten qsort
ja bsearch
, ovat ehdottomasti ei yleiset toiminnot). Ihannetapauksessa haluaisit myös kääntäjän havaitsevan automaattiset mahdolliset puhelut tähän yleiseen toimintoon ja luomaan todellisen koodin tarvittaessa.
C ++ tekee tämän helpoksi 1 tarjoamalla mallit :
template <typename T> T summation( T *values, size_t numValues ) { T result = 0; for ( size_t i = 0; i < numValues; i++ ) result += values[i]; return result; }
T
on minkä tahansa tyyppisen paikkamerkki 2 , joten voit kutsua sitä nimellä
int ivals[] = {1,2,3,4,5,6,7,8,9}; double dvals[] = {1,2,3,4,5,6,7,8,9}; int sumi = summation( ivals, 10 ); double sumd = summation( dvals, 10 );
Kun koodi on koottu, kääntäjä näkee kaksi kutsua summation
ja päättää argumenttityypit. Kullekin eri tyypille se luo funktion uuden esiintymän, jolloin sille annetaan yksilöllinen nimi:
int summation_i( int *values, size_t numValues ) // actual compilers will generate { // more complex "mangled" names int result = 0; // than this ... } double summation_d( double *values, size_t numValues ) { double result = 0; ... }
Sen jälkeen se tuottaa koodin siten, että summation_i
-tulos osoitetaan ryhmälle sumi
ja summation_d
osoitetaan ryhmään sumd
.
C ei tarjoa mitään vastaavaa kuin malliominaisuus. Perinteisesti olemme hyökänneet yleiseen ohjelmointiin kahdella tavalla – joko makroja tai void *
kaikkialla ja delegoi tyyppitietoiset toiminnot muille toiminnoille.
Tässä on huono esimerkki makropohjaisesta ratkaisusta:
#include <stdio.h> #define SUMMATION_DEF(t) \ t summation_##t( t *values, size_t numValues ) \ { \ t result = 0; \ for ( size_t i = 0; i < numValues; i++ ) \ result += values[i]; \ return result; \ } #define SUMMATION(t,x,s) summation_##t(x, s) SUMMATION_DEF(int) SUMMATION_DEF(double) int main( void ) { int ivals[] = {1, 2, 3, 4, 5}; double dvals[] = {1, 2, 3, 4, 5}; int sumi = SUMMATION(int, ivals, 5); double sumd = SUMMATION(double, dvals, 5); printf( "sumi = %d\n", sumi ); printf( "sumd = %f\n", sumd ); return 0; }
SUMMATION_DEF
on karkeasti samanlainen kuin malli siinä mielessä, että se määrittää funktiotoiminnot käyttämällä makroparametria t
tyypin paikkamerkkinä. Käytämme myös t
osana funktion nimeä – ##
on tunnuksen liittämisoperaattori, ja esiprosessori laajenee t
ja liitä kyseinen arvo funktion 3 nimeen.
Missä se eroaa C ++: sta, on se, että makro on vain tyhjä tekstikorvaus. Se ei laukaise kääntäjän mahdolliset erityistoimenpiteet. Todellisia funktion esiintymiä ei luoda automaattisesti SUMMATION
-makron mahdollisten kutsumusten perusteella – meidän on luotava nimenomaisesti haluamasi toiminnot (tästä syystä SUMMATION_DEF(int)
ja SUMMATION_DEF(double)
ennen main
). Se tarkoittaa myös, että kun kutsumme summation_xxx
SUMMATION
-makron kautta meidän on välitettävä tyyppi osana makro-argumenttiluetteloa, jotta oikea funktio kutsutaan. Mikä tuska.
C 2011 -standardi lisäsi avainsanan _Generic
, joka voi tehdä elämästä tässä suhteessa hieman helpompaa:
#include <stdio.h> #define SUMMATION_DEF(t) \ t summation_##t( t *values, size_t numValues ) \ { \ t result = 0; \ for ( size_t i = 0; i < numValues; i++ ) \ result += values[i]; \ return result; \ } #define SUMMATION(x,s) _Generic((x), \ int * : summation_int, \ double * : summation_double \ )(x, s) SUMMATION_DEF(int) SUMMATION_DEF(double) int main( void ) { int ivals[] = {1, 2, 3, 4, 5}; double dvals[] = {1, 2, 3, 4, 5}; int sumi = SUMMATION(ivals, 5); double sumd = SUMMATION(dvals, 5); printf( "sumi = %d\n", sumi ); printf( "sumd = %f\n", sumd ); return 0; }
Avainsanan _Generic
avulla voit arvioida lausekkeita tyypit perusteella, joten jos ensimmäisen argumentin tyyppi SUMMATION
on int *
, kutsumme summation_int
; se ”se” on double *
, kutsumme summation_double
. Tällä tavalla meidän ei tarvitse määrittää tyypin nimeä makro argumenteissa.
Toinen tapa, kuten olet nähnyt, on käyttää void *
ja delegoida tyyppitietoiset toiminnot muille toiminnoille. Kuten edellä sanoin, että ” Se ei ole oikeastaan ”yleinen” ohjelmointi, koska joudut toteuttamaan kukin vertailutoiminto kullekin tyypille. Et voi ”koodata sitä vain kerran ja tehdä sen. Ja käyttämällä void *
-toimintoa, heität tyypillisen turvallisuuden ulos ikkunasta ja tulevaan liikenteeseen.
Ja ennen kuin kukaan valittaa – ei, yksikään näistä summaustoiminnoista ei tarkista tai käsittele aritmeettista ylivuotoa. Se on aihe toisen päivän ajan.
- Riittävän löyhät ”helppo” -määritelmät. Mallien tukena käytetty metaprogrammointikieli on Turing-täydellinen, joten voit tehdä * todella hämmästyttävää * ja mahdotonta ymmärtää asioita sen avulla.
- ”Kaikentyyppisten” määritelmien riittävän löyhille määritelmille. Huomaa, että minkä tahansa käyttämäsi tyypin on tuettava operaattoria
+=
, muuten kääntäjä huutaa sinua. - Tämä koodi rikkoo tyyppejä, kuten
unsigned int
tailong double
, koska niissä on tyhjää tilaa. En tiedä heti ratkaisua ongelmaan, ja olen viettänyt tarpeeksi aikaa tähän vastaukseen sellaisenaan.