2016-11-30 31 views
7

Rozumiem atrakcyjność czystych języków funkcjonalnych, takich jak Haskell, gdzie można śledzić efekty uboczne, takie jak we/wy dysku za pomocą monad.Co liczy się jako efekt uboczny? Dlaczego alokacja pamięci nie jest efektem ubocznym?

Dlaczego nie wszystkie wywołania systemowe są uważane za efekty uboczne? Na przykład przydział pamięci sterty (który jest automatyczny) w Haskell nie jest śledzony. A przydział sterty może być efektem ubocznym, chociaż nie jestem pewien, czy byłby użyteczny. Oba zmieniają ogólny stan systemu.

Więc gdzie jest linia narysowana, co jest efektem ubocznym, a co nie? Czy jest to po prostu to, co jest najbardziej "użyteczne"? Czy istnieje bardziej teoretyczny fundament?

+6

Myślę, że najprostszą odpowiedzią jest to, że jeśli alokacja byłaby efektem ubocznym, bardzo niewiele rzeczy byłoby "czystych", co zmniejsza użyteczność tego pojęcia. Purity nie ma jednej uniwersalnej rygorystycznej definicji. Mogę sobie wyobrazić język, który * zrobił * traktował alokację jako efekt uboczny i zarządzał nim przez system typów, co może być bardzo przydatne w systemach z niewielką ilością pamięci (np. Systemy wbudowane), ale nie znam żadnej taki język obecnie. –

+3

Alokacja pamięci jest efektem ubocznym, jeśli chcesz kontrolować, kiedy to się stanie. Zobacz opakowania owijające IORef/STRef/FunPtr. Chodzi o to, że jeśli dzieje się to automatycznie, możesz zaufać kompilatorowi, by był inteligentny, więc Haskell nie zmusza cię do tego, by się tym martwić. –

+0

@AlexisKing Jako ktoś, kto od czasu do czasu musi napisać kod dla systemów wbudowanych, byłby to naprawdę interesujący język do wdrożenia. Wyobrażam sobie, że można go napisać jako DSL w Haskell, ale byłby fajny jako samodzielny język, który kompilował bardzo wydajnie. – bheklilr

Odpowiedz

11

Podczas wnioskowania na ten temat musi być na poziomie teoretycznym i na poziomie specyfikacji języka, a nie na tym, jak to się robi na sprzęcie.

Język programowania nie jest tak naprawdę rzeczywistą implementacją, więc jeśli nie myślisz o C og C++, który ma alokację pamięci i syscall jako część języka, to języki wyższego poziomu, w których obsługiwane są przez prymitywy systemów, nie są częścią języka. Jeśli nie jest częścią języka, nie może być efektem ubocznym.

Rzeczywisty kod maszynowy implementacji nigdy nie byłby czysty, ponieważ sposób przekazywania argumentów i otrzymywania wartości zwracanych jest przechowywany w obu rejestrach lub stosach, zarówno przez mutację. Większość pojęć, których używamy we wszystkich nowoczesnych programach, jest tłumaczona na arytmetykę, flagi, skoki i dostęp do pamięci. Każda instrukcja CPU, z wyjątkiem NOP, modyfikuje maszynę. Program składający się tylko z NOP nie jest zbyt użyteczny.

+1

Wszystkie dobre odpowiedzi, myślę, że mylić specyfikacji dla Haskell z jego realizacji. Dzięki. Zastanawiam się teraz, czy są jakieś języki niskiego poziomu/C, które określają semantykę efektów ubocznych dla takich rzeczy jak alokacja. – relevate

+2

Ocena instrukcji procesora ma również implementację sprzętową, więc NOP mógł (równie niepomyślnie) zostać poinformowany o zmutowaniu rejestru wskaźnika instrukcji. –

+0

@thatotherguy Prawda, ale każda instrukcja oprócz NOP mutuje również coś innego niż licznik programu. – Sylwester

7

Ani alokacja stosu, ani przydzielanie sterty to coś, co można "zrobić" lub obserwować w Haskell. Dlatego nie można go traktować jako efektu ubocznego. W pewnym sensie to samo dotyczy rozgrzewania procesora, co bez wątpienia jest rozpoznawalnym efektem fizycznym działania czystego kodu Haskela.

Tak się składa, że ​​niektóre implementacje Haskella na współczesnym sprzęcie i systemie operacyjnym przydzielają stos/stertę podczas działania kodu, ale nie można tego zaobserwować na podstawie kodu.

+0

"Tak się składa, że ​​niektóre implementacje Haskella na współczesnym sprzęcie i systemie operacyjnym przydzielają stos/stertę w trakcie działania twojego kodu" - i jak! – jberryman