2011-01-08 26 views
6

Tôi muốn có một chức năng như:Có cách nào hợp lý để giải nén đơn nguyên trạng thái không?

unzipState :: (MonadState s m) => m (a, b) -> (m a, m b) 

trong đó sẽ có một (stateful) tính toán rằng trả về một tuple, và sẽ quay trở lại hai phép tính (phụ thuộc).

Khó khăn là tất nhiên trong đó trích xuất các giá trị từ một hoặc các tính toán khác nên cập nhật trạng thái trong khác.

Một hữu ích (và động cơ thúc đẩy) ứng dụng là đơn nguyên ngẫu nhiên, thể hiện dưới dạng

{-# LANGUAGE Rank2types #-} 
import qualified System.Random as SR 
import Control.Monad.State 

type Random a = forall r. (State RandomGen r) => State r a 

và giả sử bạn có:

normal :: Random Double 
-- implementation skipped 

correlateWith :: Double -> Random (Double, Double) -> Random (Double, Double) 
correlateWith rho w = do 
         (u, v) <- w 
         return $ (u, p * u + (1 - p * p) * v) 

nó sẽ là khá tự nhiên để có thể viết:

let x = normal 
    y = normal 
    (u, v) = unzipState $ correlateWith 0.5 $ liftM2 (,) x y 
    ... now I am able to perform computation on u and v as correlated random variables 

Có cách nào hợp lý để thực hiện việc này không? Tôi đã vật lộn một chút, nhưng không xoay sở được gì cả. Hoogle cũng chẳng giúp được gì.

chỉnh sửa

câu trả lời lớn đã cho tôi thấy vấn đề của tôi là mập mờ. Tuy nhiên, ai đó có thể giải thích cho tôi lý do tại sao thực hiện sau đây trong python (mà tôi tin là đúng, nhưng chưa được thử nghiệm nhiều) không thể dịch được trong Haskell (với sự kỳ diệu của STrefs, đóng cửa và những thứ khác tôi thừa nhận tôi không nắm ;-)):

def unzipState(p): 
    flist, glist = [], [] 
    def f(state): 
     if not flist: 
      (fvalue, gvalue), newstate = p(state) 
      glist.insert(0, gvalue) 
      return (fvalue, newstate) 
     else: 
      fvalue = flist.pop() 
      return (fvalue, state) 
    def g(state): 
     if not glist: 
      (fvalue, gvalue), newstate = p(state) 
      flist.insert(0, fvalue) 
      return (fvalue, newstate) 
     else: 
      gvalue = glist.pop() 
      return (gvalue, state) 
    return (f, g) 

không phải là tôi nói rằng mã stateful có thể được dịch trong Haskell, nhưng tôi cảm thấy như sự hiểu biết lý do tại sao khi (ngay cả trên một ví dụ) nó không thể được thực hiện sẽ nâng cao hiểu biết của tôi rất nhiều.

edit2

Bây giờ nó là tinh thể rõ ràng. Các functons f và g rõ ràng là không thuần túy, vì đầu ra của chúng không chỉ phụ thuộc vào giá trị của trạng thái.

Cảm ơn bạn lần nữa!

Trả lời

5

Đó là không thể để tạo chức năng chung unzipState thực hiện những gì bạn muốn, nếu chỉ vì bạn có thể không cung cấp đặc điểm chính thức cho hiệu quả dự định của nó. Nói cách khác, giả sử rằng bạn đã thực hiện một số chức năng unzipState. Làm thế nào để bạn biết rằng nó là chính xác? Bạn sẽ phải chứng minh rằng nó đáp ứng một số luật/phương trình, nhưng vấn đề ở đây là tìm những luật này ngay từ đầu.


Trong khi tôi nghĩ rằng tôi hiểu những gì bạn muốn làm, đơn vị Random cũng làm cho nó rõ ràng lý do tại sao nó không thể được thực hiện. Để thấy rằng, bạn phải bỏ cái dự án thực hiện cụ thể type Random a = ... và xem xét việc giải thích trừu tượng do

v :: Random a nghĩa là v là một phân phối khả các giá trị của loại a

Các "ràng buộc" hoạt động (>>=) :: Random a -> (a -> Random b) -> Random b chỉ đơn giản là cách để xây dựng phân bố xác suất mới từ phân phối xác suất cũ.

Bây giờ, điều này có nghĩa là unzipState chỉ đơn giản trả về một cặp phân phối xác suất, có thể được sử dụng để xây dựng các bản phân phối xác suất khác. Vấn đề là trong khi cú pháp do có vẻ rất gợi ý, nhưng bạn không thực sự lấy mẫu các biến ngẫu nhiên, bạn chỉ tính toán phân phối xác suất. Các biến ngẫu nhiên có thể được tương quan, nhưng phân phối xác suất không thể.


Lưu ý rằng có thể tạo một đơn nguyên khác nhau RandomVariable a tương ứng với các biến ngẫu nhiên. Tuy nhiên, bạn phải sửa không gian mẫu Ω trước. Việc thực hiện là

type RandomVariable a = Ω -> a 



Nếu bạn muốn cả hai biến ngẫu nhiên và khả năng mở rộng không gian mẫu tự động, bạn có thể cần hai thao tác bind

bind1 :: Random Ω a -> (a -> Random Ω b) -> Random Ω b 
bind2 :: Random Ω1 a -> (a -> Random Ω2 b) -> Random (Ω1,Ω2) b 

và một số phụ thuộc loại ma thuật để đối phó với sự gia tăng của các sản phẩm như (Ω1,(Ω2,Ω3)).

+0

Tôi không nghĩ rằng (Random a) thực sự có thể được hiểu là phân phối xác suất bởi vì trong trường hợp đó, bạn cần có khả năng xác định omega là một không gian được lập trình, điều này khá khó. Hơn nữa, không phải vì hai đối tượng của Random a có cùng phân phối giống nhau (lấy hai u = uniform; v = uniform, bạn don 'có u = v). Một cách giải thích khiêm tốn hơn là hiểu nó như là sự hiện thực hóa (cụ thể hơn, như các hàm hoạt động trên sự hiện thực hóa) của các biến ngẫu nhiên, cần phải đồng nhất với các luồng, vì vậy tôi tin rằng hoạt động giải nén được xác định rõ). – LeMiz

+0

Không. Nếu 'u = uniform :: Random A' và' v = uniform :: Random A', thì đúng là trivially true 'u = v = uniform'. Hãy nhớ rằng có hai khái niệm khác nhau ở đây: các biến ngẫu nhiên bắt nguồn từ một không gian mẫu Ω, và các tập hợp các giá trị kiểu 'a' có trọng số xác suất (= phân bố xác suất). Chữ 'Random a' của bạn tương ứng với chữ cái thứ hai, không phải là cái cũ. Cũng có thể thực hiện nó như là 'Random a = [(a, Probability)]'. [Tôi sợ có một chút khó khăn khi thảo luận về điều này mà không cần chính thức hóa đơn nguyên mẫu ngẫu nhiên và hiệu ứng cụ thể mà bạn đang làm.] –

+0

bạn hoàn toàn đúng về điểm bình đẳng, tôi đã nhầm lẫn. Cảm ơn ! – LeMiz

3

Tôi không hoàn toàn rõ ràng về cách bạn muốn điều này hoạt động - kể từ khi correlateWith hoạt động trên bộ dữ liệu, các biến tương quan có ý nghĩa gì độc lập? Giả sử bạn làm điều này:

let x = normal 
    y = normal 
    (u, v) = unzipState $ correlateWith 0.5 $ liftM2 (,) x y 
in do u1 <- u 
     v1 <- v 
     u2 <- u 
     u3 <- u 
     -- etc... 

mối quan hệ gì nên tồn tại giữa u1, u2, và u3?

Ngoài ra, một "biến ngẫu nhiên" như thế này có thể được chuyển đổi thành luồng lười vô hạn theo cách đơn giản. Ý nghĩa của những điều sau đây sẽ là gì?

let x = normal 
    y = normal 
    (u, v) = unzipState $ correlateWith 0.5 $ liftM2 (,) x y 
in do vs <- generateStream v 
     u1 <- u 
     if someCondition u1 then u else return u1 
     -- etc... 

Vì số lượng các giá trị lấy mẫu từ u thay đổi dựa trên u1, điều này dường như cho thấy rằng giá trị phi monadic ràng buộc để vs sẽ hồi tố phụ thuộc phần nào vào u1 là tốt, mà âm thanh nghi ngờ giống như các loại ma quái hành động ở khoảng cách mà Haskell tránh được.

Tôi sẽ nguy hiểm khi đoán rằng những gì bạn đang cố gắng hoàn thành không thể đơn giản được trang bị thêm trên đơn vị trạng thái PRNG đơn giản, nhưng có thể có các tùy chọn khác.

+0

Tôi đoán ngữ nghĩa sẽ giống hệt như Luồng: Luồng dữ liệu a = a: (a: LeMiz

+0

trong phần trước nhận xét, vui lòng đọc (u1, v1) có mối tương quan thay vì (u1, u2) tương quan. – LeMiz

0

Có rất nhiều thứ liên quan đến các mones Bayes ở Haskell.Dưới đây là một tài liệu tham khảo: http://www.randomhacks.net/articles/2007/02/22/bayes-rule-and-drug-tests

Xem thêm "Hoàn toàn chức năng lười biếng lập trình không xác định" có sẵn từ trang này: http://www.cs.rutgers.edu/~ccshan/

Chỉnh sửa: Tôi cũng không hiểu tại sao bạn không thể chỉ cho correlateWith chữ ký loại sau đây, và chạy nó bên trong khối lệnh trực tiếp thay vì cố gắng "đẩy" trạng thái ngẫu nhiên trong một ràng buộc cho phép. correlateWith :: Double -> Random Double -> Random Double -> Random (Double, Double)

+0

Đây là tài liệu thú vị, nhưng bạn có thể chỉ cho tôi cách nó liên quan đến vấn đề của tôi không? – LeMiz

+0

Nó cho thấy làm thế nào để làm monads xác suất thực tế, thay vì chỉ quá tải ngẫu nhiên và không. – sclv

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