2012-03-22 37 views
5

Trong another question, tôi đã hỏi về các đa thức đồng thời cho Java.Chức năng tương đương với đa đồng thời

Có một số mẫu lập trình chức năng (không thay đổi) có thể được sử dụng thay thế trong chương trình Scala hoặc Clojure không? Tôi hình dung rằng giải pháp Scala có lẽ sẽ liên quan đến các diễn viên và một clojure một atom, ref hoặc agent, nhưng có thể có một cách tốt hơn. Vì cả hai ngôn ngữ đều cho phép "rơi ngược" vào Java interop và chỉ sử dụng giải pháp Java, tôi có thể sử dụng bất kỳ câu trả lời nào cho câu hỏi đầu tiên của mình, nhưng điều đó sẽ không tuân theo mô hình lập trình hàm. Làm thế nào để lập trình viên Haskell giải quyết vấn đề này?

+1

Đó là một quan niệm sai lầm phổ biến mà Haskell không cho phép đột biến. Nó có. Việc nắm bắt là tất cả các đột biến phải được ghi nhận hợp lệ trong các loại; do đó cách điển hình để tạo ra các hoạt động đột biến cùng nhau là với giao diện đơn nhất. Haskellers có thể "rơi trở lại" để biến đổi theo cách tương tự như Scala và Clojure, ngoại trừ trong Haskell bạn không thể ăn gian và làm cho nó trông giống như một chức năng là tinh khiết khi nó không phải là. Tuy nhiên, nếu bạn có thể đóng gói hoàn toàn đột biến trong hàm của mình, thì nó vẫn có thể phơi bày một giao diện thuần túy. –

Trả lời

7

Bản đồ và bộ bản đồ Clojure chuẩn là không thay đổi (và liên tục) [1], vì vậy chúng hoạt động tốt trong các chương trình đồng thời. Bạn có thể muốn lưu trữ chúng trong một ref/agent/var/atom tùy thuộc vào yêu cầu của bạn, và bạn chỉ có thể cập nhật ref/agent/var/atom bao giờ hết.

Bạn có thể có một bản đồ có thể thay đổi nhiều hơn, nếu các giá trị thực sự là refs, như thế này:

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

Trong trường hợp này, bạn sẽ có thể để thực sự thêm giá trị cho chìa khóa (trong giao dịch đã tồn tại khóa học). Bổ sung và loại bỏ các phím vẫn sẽ trở lại bản đồ mới, trong đó sẽ chia sẻ những refs giống như các bản đồ gốc, và do đó thay đổi một trong số họ sẽ hiển thị cho những người khác:

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] Nghĩa là, thêm/xóa/sửa đổi khóa và giá trị thực sự trả lại bản đồ mới, mà không thay đổi bản gốc.

3

Cấu trúc dữ liệu chức năng là cấu trúc dữ liệu không thay đổi. Cấu trúc dữ liệu không thay đổi không có vấn đề với đồng thời vì chúng không thể sửa đổi được.

+0

Là một diễn viên (hoặc diễn viên giống như lớp) cách duy nhất an toàn thread để quản lý cấu trúc dữ liệu này. – Ralph

+2

@Ralph không hề. Các diễn viên rất hữu ích, nhưng chúng không phải là sự bắt kịp cho bất kỳ vấn đề tương tranh nào. Như Daniel nói, bạn không cần bất kỳ loại quản lý nào của một cấu trúc bất biến. Câu hỏi sau đó sẽ trở thành cho dù bạn cần sự biến đổi, và nếu như vậy theo cách nào. Chi tiết hơn sẽ giúp ích ở đây. – Submonoid

Các vấn đề liên quan