Powodem, dla którego tak bardzo lubię Rcpp, jest to, że nie zawsze rozumiem, jak myśli R Core, aw przypadku Rcpp częściej niż nie muszę.
Mówiąc filozoficznie, jesteś w stanie grzechu w odniesieniu do paradygmatu funkcjonalnego, który stara się zapewnić, że każda wartość wydaje się niezależna od każdej innej wartości; zmiana jednej wartości nigdy nie powinna powodować widocznej zmiany innej wartości, tak jak w przypadku wskaźników udostępniających reprezentację w C.
Problemy pojawiają się, gdy programowanie funkcjonalne sygnalizuje małemu statkowi, aby usunął się z drogi, a mały statek odpowiada „Jestem latarnią morską”. Dokonanie długiej serii małych zmian w dużym obiekcie, na którym chcesz w międzyczasie przetworzyć, umieszcza kwadrat na terytorium latarni morskiej.
W C ++ STL push_back()
to sposób na życie. Nie stara się być funkcjonalny, ale stara się efektywnie dostosowywać popularne idiomy programowania .
Mając trochę sprytu za kulisami, możesz czasem ustawić jedną stopę w każdym świecie. Dobrym przykładem są systemy plików oparte na migawkach (które wyewoluowały z takich koncepcji, jak łączenie montowań, które również obejmują obie strony).
Gdyby R Core chciał to zrobić, bazowa pamięć wektorowa mogłaby działać jak sumator. Jedno odniesienie do pamięci wektorowej może być ważne dla indeksów dolnych 1:N
, podczas gdy inne odniesienie do tego samego magazynu jest ważne dla indeksów dolnych 1:(N+1)
. Może istnieć zarezerwowane miejsce do przechowywania, do którego nie ma jeszcze ważnego odniesienia, ale wygodne dla szybkiego push_back()
. Nie naruszasz koncepcji funkcjonalnej, gdy dołączasz poza zakresem, który jakiekolwiek istniejące odniesienie uważa za prawidłowe.
Ostatecznie dodając wiersze przyrostowo, zabraknie zarezerwowanego miejsca. Będziesz musiał utworzyć nowe kopie wszystkiego, pomnożąc przestrzeń dyskową przez pewien przyrost. Implementacje STL, których używam, mają tendencję do mnożenia pamięci przez 2 podczas rozszerzania alokacji. Myślałem, że przeczytałem w R Internals, że istnieje struktura pamięci, w której pojemność zwiększa się o 20%. Tak czy inaczej, operacje wzrostu występują z częstotliwością logarytmiczną w stosunku do całkowitej liczby dołączonych elementów. Na zasadzie amortyzacji jest to zwykle dopuszczalne.
W miarę jak chodzą za kulisami sztuczki, widziałem gorzej. Za każdym razem, push_back()
gdy dodajesz nowy wiersz do ramki danych, należałoby skopiować strukturę indeksu najwyższego poziomu. Nowy wiersz może zostać dołączony do wspólnej reprezentacji bez wpływu na jakiekolwiek stare wartości funkcjonalne. Nie sądzę nawet, żeby to zbytnio skomplikowałoby śmieciarza; ponieważ nie proponuję, że push_front()
wszystkie odwołania są prefiksami z przodu przydzielonej pamięci wektorowej.
append()
[który prawdopodobnie powinien się nazywać insert] lubc()
dodać elementy na koniec listy, ale nie pomoże ci tutaj.