Getters and Setters in Functional Languages

9

Jednym z założeń programowania funkcjonalnego jest stosowanie funkcji czystych. Funkcja Pure to taka, która nie powoduje skutków ubocznych i jest względnie przezroczysta.

Gettery nie są referencyjnie przezroczyste - jeśli Setter jest wywoływany między wywołaniami Gettera, wartość zwrotna Gettera zmienia się, mimo że jego parametry nie (zwykle nie ma parametrów)

Setery wywołują skutki uboczne - Wywołanie Setera zwykle manipuluje wartością, która nie jest jego wartością zwracaną (w rzeczywistości, tradycyjnie setter nic nie zwraca)

Wiem, że w Scali po prostu akceptujemy fakt, że łączymy ze sobą dwa paradygmaty (funkcjonalny i obiektowy) i używamy getterów / setterów tak, jak robilibyśmy w języku takim jak Java.

W języku takim jak Haskell (z którym nie jestem biegły, ale powiedziano mi, że bardziej odpowiada „czystemu” językowi funkcjonalnemu) jestem po prostu ciekawy, w jaki sposób można modelować właściwości obiektów, tak aby Getters były referencyjnie przezroczyste, a Settery są wolne od skutków ubocznych?

Czy rozwiązaniem byłoby przekazanie z powrotem kopii obiektu, na który wywołano setera, jako wartości zwracanej przez setera, a ta kopia zawiera zmianę wartości właściwości?

ThaDon
źródło
8
Obiekty pobierające i ustawiające mają obiekt jako parametr - mimo że zwykle jest to domniemane - więc obiekty pobierające względnie przezroczyste.
@ delnan, tylko jeśli atrybut, który odczytuje, jest niezmienny.
dan_waterworth
3
@dan_waterworth: Tylko jeśli odczytamy „to samo” w „referencyjnie przezroczystym” jako tożsamość obiektu. Jeśli fakt, że podstawowy atrybut jest inny, powoduje, że jest to wywołanie z różnymi argumentami (co jest zgodne z większością definicji równości). Jest to ignorowanie innego wątku wywołującego setera i kończącego go między wywołaniem gettera a ukończeniem gettera, ale w takim przypadku i tak masz poważniejsze problemy.

Odpowiedzi:

7

Dokładnie. Zobacz metodę klasy przypadków copylub ogólną koncepcję soczewek.

W szczególności, jeśli stan wymaga zmiany, użyłbyś monady stanu. Zmiany w tej monadzie stanu można wprowadzać za pomocą soczewek, co ułatwia wydobywanie informacji z „stanu” i zmianę ich.

Zobacz także to pytanie dotyczące ogólnego problemu wynikającego z głębokiej struktury, takiej jak „stan” i wprowadzania w nim zmian. Odpowiedzi mają dobre linki zarówno na soczewkach, jak i na suwakach, jeśli chcesz się w to zagłębić.

Daniel C. Sobral
źródło
Pytanie Daniel: czy istnieje jakiś szczególny powód, dla którego copy () jest powiązany z klasami Case? Nie wydaje się to specyficzne dla potrzeb (niewłaściwe słowo, ale nie może wymyślić innego) klas Case, wydaje mi się (bardziej) cechą odpowiednią dla wszystkich klas. Co się stanie, jeśli będę potrzebował funkcji copy () w mojej klasie, która nie ma przypadku? Czy jest jakaś funkcja, której mogę użyć, aby uzyskać tę funkcjonalność?
ThaDon
1
Klasy przypadków @ThaDon powinny być definiowane przez parametry konstruktora - ich równość, kod skrótu i ​​ekstraktor są oparte na tym założeniu, podobnie jak metoda kopiowania. W przypadku klas, które nie są przypadkami, każdy zgaduje, czy parametry konstruktora są wszystkim, co jest potrzebne do skopiowania klasy. Możesz jednak łatwo napisać własną metodę kopiowania.
Daniel C. Sobral
11

Cóż, w Haskell obiekty są (zwykle) niezmienne, więc gettery (które otrzymujesz, gdy używasz składni rekordu) lub funkcje, które działają jak gettery, względnie przezroczyste. A potem nie „ustawiasz” wartości na obiektach - jeśli cokolwiek tworzysz nowy obiekt, który jest podobny do starego, ale z inną wartością dla jednego z pól. Jest to również czysta funkcja.

MatrixFrog
źródło
1
„obiekty są (zwykle) niezmienne”, kiedy nie są?
sara
-1

„Operatory pobierające i ustawiające mają obiekt jako parametr - mimo że zwykle jest to domniemane - więc funkcje pobierające są względnie przezroczyste. - delnan”

Referencyjnie przezroczysty oznacza, że ​​funkcja ZAWSZE zwraca to samo wyjście dla tych samych danych wejściowych; więc jeśli atrybut obiektu został zmieniony przez narzędzie ustawiające, nie zwraca się tego samego wyniku. :)

Casey Hawthorne
źródło
Ale jeśli obiekt został zmieniony przez ustawiającego, dane wejściowe do gettera (tj. Domyślny argument własny) HAS uległy zmianie.
Stephen C. Steel
1
Wartość / wskaźnik odwołania do obiektu nie zmienił się, chyba że obiekt został przeniesiony na stercie.
Casey Hawthorne
5
Tak, ale logicznie, niejawne dane wejściowe to sam obiekt, a nie wartość wskaźnika.
Stephen C. Steel
„jeśli atrybut obiektu został zmieniony przez ustawiającego, nie zwracasz tego samego wyniku”: Pod względem funkcjonalnym zniszczyłeś pierwszy obiekt i utworzyłeś nowy. Ze względu na wydajność (unikaj kopiowania i aktualizacji odniesień ze starego do nowego obiektu) nowy obiekt przechowujesz w tym samym obszarze pamięci, który zawierał stary obiekt.
Giorgio