2014-09-21 26 views
17

Zasadniczo jestem ciekawy, czy kod jak:Czy tworzenie (nie-listowej) struktury danych za pośrednictwem fromList faktycznie tworzy listę?

let myCollection = Data.SomeCollection.fromList [1, 2, foo] 

faktycznie robi to, co wygląda jak w czasie wykonywania i tworzenia połączonej listy jako etap pośredni w tworzeniu SomeCollection -lub jeśli jest to tylko wygoda składniowa i kompilator unika tworzenia listy w skompilowanym kodzie?

Przepraszam, jeśli to głupie pytanie, ale od czasu do czasu dowiedziałem się czegoś o Haskellowi.

+1

Być może zechcesz wyjaśnić, czy pytasz o "Wektor", czy bardziej ogólnie o każdy typ. "Wektor" jest szczególnym przypadkiem, ponieważ prawdopodobnie zawiera reguły przepisywania specyficzne dla grafiki wektorowej w celu zlikwidowania pośrednich list. –

+0

@GabrielGonzalez dziękuję, redagowałem, aby wyjaśnić, że jestem zainteresowany, jeśli zachodzi specjalna obsługa dla każdej kolekcji z 'fromList', choć jeśli tylko * niektóre * eliminują listę (np." Vector "na przykład), to jest również dobre do wiem –

+1

Obawiam się, że zazwyczaj będziesz musiał założyć, że będzie to lista rzeczywista, chyba że wspomniana wyżej specjalistyczna optymalizacja "wektorowa" lub podobne kopnięcie. – leftaroundabout

Odpowiedz

12

Krótka odpowiedź: Być może, w pewnym sensie, ale nie bardzo ...

Dłuższe Odpowiedź:

Kiedy mówisz listy myślisz w kategoriach nadrzędnych powiązane. Haskell jest leniwy i funkcjonalny, co sprawia, że ​​trudno jest odpowiedzieć na to pytanie.

[a,b,c] jest krótką ręką dla a:(b:(c:[])). Jeśli w pełni to oceniamy (na przykład spróbujmy go wydrukować), to co kończy się w pamięci wygląda i działa podobnie jak lista połączona w C, ale o wiele więcej mózgów. Ale to nie jest zwykle to, co dzieje się z listą w ustawieniu funkcjonalnym. Funkcjonalność większości funkcji opartych na listach polega na tym, że robimy coś z szefem listy i wysyłamy ogon listy w inne miejsce (być może w to samo miejsce). Oznacza to, że lista naprawdę wygląda x:xs gdzie xs to tylko niektóre funkcje, które utworzą resztę listy. (thunk w terminologii GHC)

Cała lista nie jest tworzona, a następnie przetwarzana tak, jak w imperatywnym języku. Jest on przesłany za pomocą funkcji poprzez jedną część na raz.

Przynajmniej tak działają większość funkcji fromList. Ogólny fromList dla kolekcji może wyglądać tak:

fromList :: [a] -> Collection a 
fromList = Data.List.foldl' insert empty 

Niektóre zbiory mogą skorzystać z posiadania więcej niż jednego elementu dodanego naraz. Te kolekcje (i nie znam żadnych, ale wiem, że istnieją) zbudują obszerniejszą listę pamięci.

Poza optymalizacje kompilatora, jednak jest to na ogół tak, że

jest obliczeniowo równoważne (w maleńkim stały współczynnik) od:

empty `insert` 1 `insert` 2 `insert` foo 

Zastrzeżenie: ja nie znać wewnętrzne elementy każdej implementacji Haskella na tyle dobrze, by z absolutną pewnością powiedzieć, jak oceniają stałą listy w kodzie, ale nie jest to zbyt daleko od rzeczywistości. Oczekuję oświecenia od guru GHC, jeśli znajdę się poza bazą.

+0

Ach, masz rację, nie myślałem o "lenistwie". To ma sens i prawdopodobnie ma wiele do złagodzenia jakiejkolwiek nieefektywności, zakładając, że łańcuch 'insert's nie powoduje paczki realokacji + kopiowania (jeśli jakieś kolekcje używają podstawowych tablic, mam na myśli - choć myślę, że drzewa są tym bardziej wspólne podejście Haskella?) –

+0

Co masz na myśli przez "Kiedy mówisz, że lista linków myślisz w kategoriach imperatywnych"? –

+0

W językach obowiązkowych połączona lista jest strukturą danych ze wskaźnikiem pamięci do następnego elementu. Na jego powierzchni komórka CONS w języku funkcjonalnym wygląda podobnie, ale oczekiwanie, że takie komórki rzeczywiście będą istniały jednocześnie w pamięci maszyny, jest nieprawidłowe. Próba konceptualizacji list funkcjonalnych, tak jak można je zaimplementować w Javie lub C, prowadzi do nieprawidłowej intuicji na temat wykorzystania algorytmów funkcjonalnych w przestrzeni czasu i przestrzeni. –