[nem-pl] in_tail_position
Lukasz Kaiser
kaiser at tenet.pl
Fri Mar 12 14:28:07 CET 2004
Hej.
> Chyba rozumiem. Jakie¶ inne przyk³ady oprócz liczb naturalnych, gdzie to
> by mog³o byæ u¿yteczne?
Jakies przyklady moglbym na sile wymyslic, ale raczej nie liczylbym na
zbyt wiele. Ogolnie wprowadzanie akumulatorow jest zbyt trudne zeby to
robic automatycznie a takie rzeczy sa po prostu uwzglednianiem latwych
szczegolnych przypadkow. Mimo tego mysle, ze i tak fajnie jest zrobic
cos takiego, zeby sie moc pochwalic, ze makr sie da tez uzywac do
optymalizacji.
> To siê nazywa destination passing style.
>
> Ogólnie w Nemerle to jest do¶æ ciê¿kie, gdy konstruktory mog± robiæ
> cokolwiek. Gdyby dodaæ im jakie¶ api do zmieniania w jaki¶ bezpieczny
> sposób mo¿e to by by³o fajne.
To chyba dawaloby dosc duzy wzrost wydajnosci, gdyby mozna bylo jakos
wykrywac ktore konstruktory sa czysto funkcjonalne. To tez ladnie
funkcjonuje z rzeczami bez wskaznikow, bo wtedy da sie reusowac pamiec.
Co myslicie o czyms takim, zeby dodac dwa atrybuty do jezyka:
- pointerless do zmiennych,
- sideefectless do konstuktorow.
Atrybut do konstruktorow w zasadzie nie jest konieczny, wystarczy
ze beda go mialy automatycznie generowane konstruktory dla variantow
i rekordow, tych jest i tak dosc duzo.
Wtedy mozna sie pokusic o taka optymalizacje, ze jesli sideefectless
konstruktor jest in tail position, to zostaje przesuniety wczesniej
a rzeczy wywolywane w jego srodku sa podstawiane w odpowiednie miejsca.
To znaczy Cons ( f(x), g(y) ) zamienia sie na def y = Cons ( null, null ),
y.a <- f(x); y.b <- g(y);. Oczywiscie to sie dzieje przy generacji kodu,
to znaczy tak, zeby elementy konstruktora mogly byc immutable w systemie
typow, ale mimo to zeby miec do nich dostep jak do wskazniow (malo
eleganckie, wiem, ale moze wydajne).
Druga mozliwa optymalizacja to jesli wywolujemy ladny konstruktor
a wczesniej byla pointerless zmienna ktora zostala rozbita z tym
samym kontruktorem, to omijamy to wywolanie i po prostu podstawiamy.
Zamierzony efekt np. dla append'a:
append ( pointerless x, y ) { match x with
| Nil => y
| z :: zs => z :: append ( zs, y )
}
Pierwsza optymalizacja powinna spowodowac, ze to bedzie ogonowe,
czyli zamiast wywolania { v <- append ( zs, y ); Cons ( z, v ) ; }
bedzie { v <- Cons ( null, null ) ; v.hd <- z ; v.tl <- append ( zs, y ); }.
Tutaj jeszcze bedzie problem, zeby nie pomieszac kolejnosci.
Natomiast druga optymalizacja powinna spowodowac, ze zamiast tworzyc
nowego Consa bedzie uzyty ten stary z lewej strony. To powinno umozliwic
naprawde wydajne kompilowanie takich rzeczy.
Myslicie, ze to jest rabialne czy zupelnie bez sensu ?
- lk
More information about the devel-pl
mailing list