2015-06-01 17 views
6

Tôi hiện đang thiết kế một thuật toán số như là một phần của hoạt động yêu cầu cập nhật vectơ doubles nhiều lần. Do thực tế là thuật toán phải là không gian và thời gian hiệu quả nhất có thể, tôi không muốn mã kiểu mã FP truyền thống tạo ra nhiều phiên bản cấu trúc dữ liệu dưới mui xe sau mỗi thao tác trên nó. Tôi cũng không muốn tạo cấu trúc dữ liệu có thể thay đổi được và có sẵn trên toàn cầu. Do đó, tôi đã quyết định sử dụng cấu trúc dữ liệu có thể thay đổi nhưng sau đó chọn thực hiện các hoạt động có thể thay đổi trong đơn vị State. Do đây là đâm đầu tiên của tôi tại sử dụng một đơn nguyên State, tôi muốn khẳng định cho dù tôi có hay không cóĐộ tinh khiết, tính minh bạch tham chiếu và đơn vị trạng thái

  1. bảo quản minh bạch tham chiếu
  2. duy trì độ tinh khiết chức năng

Chức năng update chuyển tiếp dữ liệu trạng thái cấu trúc. Vì bản cập nhật phá hoại được bản địa hóa trong hàm này và việc xử lý cấu trúc dữ liệu không thể có được từ bên ngoài, tôi nghĩ rằng hàm này là thuần khiết và tham chiếu trong suốt.

def update(i : Int,d : Double) = State[ArraySeq[Double], Unit]{ 
    case xs: ArraySeq[Double] => {xs(i) = d; (xs,())} 
} 

Chức năng app là một hàm đồ chơi đó sẽ tiêu thụ một chuỗi các double s và sửa đổi nó là trạng thái:

def app : State[ArraySeq[Double], Unit] = for{ 
    _ <- update(0, 3.142) 
    // do a heap of stuff on ArraySeq 
}yield() 

Gọi:

app(Vector(0.0, 1.0, 2.0, 3.0, 4.0).to[ArraySeq])._1.to[Vector] 

Kết quả:

res0: Vector[Double] = Vector(3.142, 1.0, 2.0, 3.0, 4.0) 
+0

Bạn có đang sử dụng trạng thái của scalaz hoặc bạn đã tự viết cho mình không? – Daenyth

Trả lời

11

Tôi đoán bạn có thể nói rằng update của bạn chính nó là tinh khiết, theo nghĩa là nó chỉ đại diện một số đột biến, nhưng ngay sau khi bạn chạy nó tất cả các cược đang tắt:

scala> val xs = List(1.0, 2.0, 3.0).to[ArraySeq] 
xs: scala.collection.mutable.ArraySeq[Double] = ArraySeq(1.0, 2.0, 3.0) 

scala> update(0, 10).eval(xs) 
res0: scalaz.Id.Id[Unit] =() 

scala> xs 
res1: scala.collection.mutable.ArraySeq[Double] = ArraySeq(10.0, 2.0, 3.0) 

Đây là một cảnh xấu, và nó ngược lại với sự trong suốt hoặc trong suốt.

State không thực sự mua cho bạn bất kỳ thứ gì trong ví dụ của bạn — thực tế là bạn đang gọi app theo cách mà bạn có số ArraySeq mà không ai khác có thể thay đổi được. Bạn cũng có thể nhẫn nhục chịu đựng và làm việc với một cấu trúc dữ liệu có thể thay đổi theo cách thông thường trong một phạm vi mà bạn kiểm soát-ie, viết app như thế này:

def app(xs: Vector[Double]): Vector[Double] = { 
    val arr = xs.to[ArraySeq] 
    // Perform all your updates in the usual way 
    arr.toVector 
} 

Điều này thực sự tinh khiết và referentially minh bạch, nhưng nó cũng trung thực hơn phiên bản State. Nếu tôi thấy giá trị loại State[Foo, Unit], giả định của tôi là giá trị này đại diện cho một số loại hoạt động thay đổi Foo thành một Foo, mới mà không cần biến đổi Foo ban đầu. Đây là tất cả các đơn nguyên trạng thái - nó cung cấp một cách tốt đẹp của mô hình hoạt động trên cấu trúc dữ liệu bất biến và sáng tác chúng theo một cách trông giống như đột biến. Nếu bạn kết hợp nó với đột biến thực tế, bạn có khả năng gây nhầm lẫn với bất kỳ ai sử dụng mã của bạn.

Nếu bạn thực sự muốn đột biến và thuần khiết thực sự cùng một lúc, bạn có thể xem số STArray của Scalaz. Đó là một giải pháp rất thông minh cho vấn đề này, và trong các ngôn ngữ như Haskell, đó là một cách tiếp cận có ý nghĩa rất nhiều. Cảm giác của riêng tôi là nó luôn là giải pháp sai lầm ở Scala. Nếu bạn thực sự cần hiệu suất của một mảng có thể thay đổi, chỉ cần sử dụng một mảng có thể thay đổi cục bộ và đảm bảo rằng bạn không bị rò rỉ nó vào thế giới bên ngoài. Nếu bạn không cần loại hiệu suất đó (và hầu hết thời gian bạn không sử dụng), hãy sử dụng một cái gì đó như State.

+1

Hút thuốc lá! Điểm lấy về việc thay đổi cấu trúc ban đầu bên trong đơn nguyên trạng thái; Tôi có cảm giác mình đang làm điều gì đó cá nhưng không thể thấy nó là gì. Tôi đã nhìn vào 'STArray' và nó chính xác giải quyết vấn đề của tôi. Cảm ơn sự thấu hiểu và lời khuyên. –

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