2012-03-22 9 views
5

W another question, zapytałem o współbieżne multimapy dla Javy.Funkcjonalny odpowiednik współbieżnego multimapu

Czy istnieje jakiś schemat programowania funkcjonalnego (niezmienny), który może być użyty zamiast tego w programie Scala lub Clojure? Wyobrażam sobie, że rozwiązanie Scala prawdopodobnie będzie obejmować aktorów i clojure one an atom, ref lub agent, ale może być lepszy sposób. Ponieważ oba języki umożliwiają "powrót do Java" i po prostu używając rozwiązania Java, mogę użyć jakiejkolwiek odpowiedzi na moje pierwsze pytanie, ale to nie będzie zgodne z paradygmatem programowania funkcjonalnego. Jak programiści Haskell rozwiązują to?

+1

Jest to błędne przekonanie, że Haskell nie pozwala mutacji. To robi. Połów jest taki, że wszystkie mutacje muszą być należycie odnotowane w typach; dlatego typowy sposób łączenia operacji mutacji polega na interfejsie monady. Haskellerowie mogą "cofnąć się" do zmienności w taki sam sposób, jak Scala i Clojure, z wyjątkiem Haskella, którego nie można oszukiwać i sprawiać, że funkcja jest czysta, gdy nie jest. Jeśli jednak możesz w pełni enkapsulować mutację w swojej funkcji, to nadal możesz odsłonić czysty interfejs. –

Odpowiedz

7

Standardowe mapy i zestawy Clojure są niezmienne (i trwałe) [1], więc działają równie dobrze w programach współbieżnych. Możesz chcieć przechowywać je w ref/agent/var/atom w zależności od twoich wymagań i możesz po prostu zaktualizować ref/agent/var/atom jak nigdy wcześniej.

Można mieć bardziej zmienny mapę, jeśli wartości są rzeczywiście sędziowie, podobnie jak to:

{:a (ref #{1 2 3}) 
:b (ref #{4 5 6})} 

W tym przypadku, będziesz w stanie rzeczywiście dodać do już istniejących wartości klucza (w transakcji kierunek). Dodawanie i usuwanie kluczy jeszcze powróci nowe mapy, które mają te same pozycje literatury jako oryginalnych map, a więc zmiany w jednym z nich będzie widoczny dla innych:

user=> (def mmap {:a (ref #{1 2 3}) :b (ref #{4 5 6})}) 
#'user/mmap 
user=> mmap 
{:a #<[email protected]: #{1 2 3}>, :b #<[email protected]: #{4 5 6}>} 
user=> (def mmap2 (assoc mmap :c (ref #{7 8 9}))) 
#'user/mmap2 
user=> mmap2 
{:C#<[email protected]: #{7 8 9}>, :a #<[email protected]: #{1 2 3}>, :b #<[email protected]: #{4 5 6}>} 
user=> mmap 
{:a #<[email protected]: #{1 2 3}>, :b #<[email protected]: #{4 5 6}>} 
user=> (dosync (alter (:a mmap2) conj 0)) 
#{0 1 2 3} 
user=> mmap 
{:a #<[email protected]: #{0 1 2 3}>, :b #<[email protected]: #{4 5 6}>} 
user=> mmap2 
{:C#<[email protected]: #{7 8 9}>, :a #<[email protected]: #{0 1 2 3}>, :b #<[email protected]: #{4 5 6}>} 

[1] Oznacza to, że dodawanie/usuwanie/modyfikowanie kluczy, a wartości faktycznie zwracają nową mapę, bez zmiany oryginału.

3

Funkcjonalna struktura danych to niezmienna struktura danych. Niezmienne struktury danych nie mają problemów ze współbieżnością, ponieważ nie można ich modyfikować.

+0

Czy aktor (lub klasa podobna do aktora) to jedyny bezpieczny w użyciu wątku sposób zarządzania tą strukturą danych. – Ralph

+2

@Ralph w ogóle. Aktorzy są przydatni, ale nie stanowią one problemu dla wszystkich problemów związanych z współbieżnością. Jak Daniel mówi, nie potrzebujesz żadnego zarządzania niezmienną strukturą. Powstaje zatem pytanie, czy potrzebujesz mutability, a jeśli tak, w jaki sposób. Pomoże w tym więcej szczegółów. – Submonoid

Powiązane problemy