2011-12-20 16 views
5

TDPL, str. 167:W jaki sposób ta czysta funkcja może modyfikować stan nieprywatny?

dopóki stan zmienny w funkcji jest całkowicie przejściowy (tj alokowane na stosie) i prywatny (czyli nie szła w odniesieniu do funkcji, które mogą go skaza), wtedy funkcję można uznać za czystą.

import std.stdio : writeln; 

struct M{ 
    int[4] _data; 

    pure ref int opIndex(size_t i){ return _data[i]; } 
} 

pure M foo(ref M m){ 

    m[0] = 1234; 
    return m; 
} 

void main(){ 

    M m1 = M([7, 7, 7, 7]); 

    writeln(m1); 
    foo(m1); 
    writeln(m1); 
} 

// output: 
// M([7, 7, 7, 7]) 
// M([1234, 7, 7, 7]) 

Stan zmienny jest przejściowy, ponieważ znajduje się na stosie, prawda? Ale to nie jest prywatne. Więc w jaki sposób foo() może modyfikować m1?

+0

Próbowałem oczyścić tag [tag: pure], ponieważ czasami odnosi się do czystych funkcji wirtualnych, czasami do [czystej] (http://beebole.com/pure/), a czasem do [czystej ] (http://en.wikipedia.org/wiki/Pure_ (programming_language)) - między innymi. Ale nie wiem nic o [tag: d]. Czy możesz potwierdzić, czy moja edycja tagów jest właściwa? Czy [tag: czysto funkcjonalny] działałby na to pytanie - stworzyłem [tag: pure-function], więc jeśli [tag: czysto-funkcjonalny] działa, myślę, że byłoby lepiej użyć istniejącego tagu. –

+0

@RichardJPLeGuen Czysty jak w [funkcjonalna czystość] (http://en.wikipedia.org/wiki/Pure_function), więc czysta funkcja działałaby na to pytanie. czysto funkcjonalny, nie tak bardzo. – Arlen

+0

Dzięki, @Alen! –

Odpowiedz

6

został nieco rozszerzony od czasu wydania TDPL, ponieważ pure, jak opisuje TDPL, okazuje się zbyt restrykcyjne, aby mogło być przydatne poza prostymi funkcjami matematycznymi i tym podobnymi. Możesz zajrzeć na the online documentation do obecnej definicji, ale to w zasadzie sprowadza się do tego:

  1. pure funkcje nie mogą uzyskać dostęp do dowolnego modułu poziomu lub zmienne statyczne, które mogą być zmutowane w trakcie programu (muszą one być const typów wartości lub immutable, do których można uzyskać dostęp z funkcji pure).

  2. pure funkcje nie mogą wywoływać żadnych funkcji, które nie są pure.

  3. funkcje nie mogą wykonywać operacji we/wy.

To wszystko. Nie ma żadnych innych ograniczeń. Jednak są tam wymagane dodatkowe ograniczenia, jeśli funkcja pure zostanie zoptymalizowana tak, że zostanie wywołana tylko raz, nawet jeśli jest używana wielokrotnie w instrukcji. Mianowicie:

  • parametry funkcji musi być immutable lub niejawnie zamienny do immutable.

Teoretycznie można rozszerzyć do wymogu, że funkcja jest argumenty musi immutable lub pośrednio zamiany na immutable (tak, że funkcja z const parametry mogą być zoptymalizowane, gdy jest podany immutable argumentów), ale obecnie nie jest walizka.

Takie funkcje pure są czasami określane jako "silnie" pure, natomiast te, których nie można zoptymalizować, będą nazywane "słabo" pure. TDPL opisuje silnie funkcje pure. Dodano słabe funkcje pure, aby zwiększyć użyteczność pure.

Choć słabo pure funkcje może zmieniać swoich argumentów, nie mogą zmieniać stan globalny, więc kiedy są one nazywane przez silnie pure funkcji (co nie może zmienić swoje argumenty), gwarancja, że ​​silnie pure funkcja zwraca wartość zawsze będzie taka sama dla tych samych argumentów nadal trzyma. Zasadniczo, ponieważ słabe funkcje pure nie mogą zmutować stanu globalnego, są częścią prywatnego stanu silnie działającej funkcji pure, z której są wywoływane. Jest więc bardzo zgodne z tym, co opisuje Andrei w sekcji 5.11.1.1 pure jako pure Czy w TDPL, z wyjątkiem tego, że prywatny stan funkcji został rozszerzony, aby umożliwić funkcje, które mogą zmienić jego prywatny stan bez zmiany stanu globalnego .

Kolejna ważna sprawa, która została dodana, ponieważ TDPL w odniesieniu do pure jest wnioskiem funkcji. pure, i @safe są wywnioskowane dla funkcji szablonowych (chociaż nie dla normalnych funkcji). Tak więc, jeżeli funkcja szablonowa może być może być pure, teraz jest ona określona jako . Jego czystość zależy od tego, z czym jest tworzona. Tak więc staje się możliwe używanie pure z funkcjami szablonowymi, podczas gdy wcześniej, zazwyczaj nie można, ponieważ jeśli zrobiłeś to pure, to nie działałoby z nieczystą funkcją. Ale jeśli nie zrobił, aby go pure, to nie można go używać z funkcją pure, więc był to poważny problem dla pure. Na szczęście poprawki interferencji atrybutów już teraz. Tak długo, jak funkcja szablonowa jest zgodna z regułami wymienionymi powyżej, gdy jest tworzona, jest to uważane za pure.

+0

Myślę, że będę musiał pozwolić, żeby to się stało i przyzwyczaić do rzeczy takich jak "czysta pustka opIndexAssign (wartość T, size_t i) {...}" i "czysta T opIndex (size_t i) const {...} ' – Arlen

+0

Wystarczy pomyśleć o' czystej' w znaczeniu, że funkcja nie może uzyskać dostępu do zmiennego stanu globalnego, a następnie pozwolić kompilatorowi zoptymalizować go, kiedy tylko może. Tak, modyfikator 'czysty' kończy się na większej liczbie funkcji niż te, które funkcjonalnie są" czyste ", ale nadal jest tym, co sprawia, że ​​funkcjonalne" czyste "funkcje są możliwe i możliwe do optymalizacji. –

5

Odniesienie jest uważane za część parametrów funkcji, a ponieważ funkcja jest słabo czysta, można modyfikować parametry. Ze stanem this uznanym za część wejścia, funkcja nadal spełnia warunek posiadania tego samego wyjścia z tym samym wejściem.

Rozważmy następujący przykład całkowicie prawnej, która wyprowadza 2:

import std.stdio : writeln; 

struct S 
{ 
    int foo = 0; 
    pure void set(size_t i){ foo = i; } 
} 


void main() 
{ 
    S s; 
    s.set(2); 
    writeln(s.foo); 
} 

O ile mi wiadomo, po TDPL został zwolniony, definicja czystej został rozszerzony. Książka opisuje mocno czyste funkcje. Potem nastąpiły dwa wydarzenia: dodano słabo czyste funkcje, które mogą mutować swoje parametry. Dodaliśmy także czystość - wnioskowanie dla funkcji szablonu, dzięki czemu można użyć instancji funkcji szablonu, o ile jest ona czysta, nawet jeśli funkcja szablonu nie jest ozdobiona pure.

Powiązane problemy