2011-06-11 38 views

Trả lời

1

Có thể với một đơn vị State kết hợp với công cụ sửa đổi tùy chỉnh và người truy cập?

+0

Đồng ý, trông giống như một sử dụng cụ thể của 'State' đơn nguyên với tôi quá. –

-3

Tôi không nghĩ rằng có chức năng tương đương thuần túy cho mẫu trạng thái. Bởi vì lập trình hàm thuần túy không có khái niệm về trạng thái và thời gian. Mẫu trạng thái thực chất về trạng thái và thời gian. Nhưng tôi nghĩ rằng tương đương chức năng không thuần túy tồn tại, đó là luồng vô hạn được đánh giá lười biếng. Bạn có thể thực hiện nó với C# yield.

+1

FP thực sự có trạng thái. Chưa bao giờ nghe nói về monads? Thậm chí còn có một cái gì đó gọi là lập trình chức năng phản ứng để nắm bắt trạng thái biến đổi theo thời gian. – fuz

+0

xin lưu ý rằng tôi đã sử dụng các từ "thuần túy" và "không thuần túy" – Dagang

+1

Tôi không nghĩ "có" là từ đúng để kết nối "lập trình chức năng" và "trạng thái". Tôi thích nghĩ về nó như là "mô hình" - chúng ta có thể thực hiện các phép tính trạng thái bằng cách xây dựng một mô hình chức năng về ý nghĩa của trạng thái. – luqui

7

Mẫu này là một ví dụ về việc sử dụng mã số State monad, một mã số tính toán sẽ làm tăng thêm mã với trạng thái.

Đây là triển khai trong Haskell.

Một số những người giúp đỡ:

import Control.Monad.Trans.State 
import Control.Monad.IO.Class 
import Data.Char 

Hai phương thức hoạt động của chương trình

data Mode = A | B 

Các loại tính stateful với chế độ này, tăng cường với một bộ đếm.

type StateM a = StateT (Int, Mode) IO a 

Chức năng ghi, một chức năng trong bối cảnh StateM, thay đổi hành vi của nó dựa trên chế độ stateful:

writeName :: String -> StateM() 
writeName s = do 
    (n,mode) <- get 
    case mode of 
     A -> do liftIO (putStrLn (map toLower s)) 
       put (0,B) 
     B -> do let n' = n + 1 
       liftIO (putStrLn (map toUpper s)) 
       if n' > 1 then put (n', A) 
          else put (n', B) 

Chạy chương trình, tung ra một tính toán stateful ban đầu trong trạng thái Một

main = flip runStateT (0, A) $ do 
    writeName "Monday" 
    writeName "Tuesday" 
    writeName "Wednesday" 
    writeName "Thursday" 
    writeName "Saturday" 
    writeName "Sunday" 

Từ mã trên, đầu ra của chính là:

monday 
TUESDAY 
WEDNESDAY 
thursday 
SATURDAY 
SUNDAY 

Lưu ý rằng đây là giải pháp hoàn toàn chức năng. Không có bản cập nhật có thể thay đổi hoặc phá hoại trong chương trình này. Thay vào đó, trình đơn trạng thái đề ra chế độ mong muốn thông qua tính toán.

+1

Tôi sẽ không nói đây là một bảng mã trung thành: ở đây chúng ta phải khai báo tất cả các chế độ ở một nơi ('chế độ dữ liệu'), trong khi đó các khai báo mẫu wikipedia có thể được kết hợp theo kiểu mô-đun. – luqui

+0

Đó là bản dịch chuẩn cho các kiểu dữ liệu đã đóng trong ngôn ngữ kiểu ML. Rõ ràng, chúng ta có thể sử dụng các kiểu dữ liệu mở thông qua các hàm hoặc các lớp kiểu, nhưng tôi nghĩ nó không liên quan đến vấn đề này. –

+1

Tôi tò mò đó là bản dịch chuẩn, và ý bạn là gì theo tiêu chuẩn. – luqui

5

Một mã hóa:

import Data.Char (toUpper, toLower) 

newtype State = State { unState :: String -> IO State } 

stateA :: State 
stateA = State $ \name -> do 
    putStrLn (map toLower name) 
    return stateB 

stateB :: State 
stateB = go 2 
    where 
    go 0 = stateA 
    go n = State $ \name -> do 
       putStrLn (map toUpper name) 
       return $ go (n-1) 

Đừng để bị lừa bởi các IO, đây là một bản dịch tinh khiết của mẫu đó (chúng tôi không sử dụng một IORef để lưu trữ các tiểu bang hoặc bất cứ điều gì). Mở rộng newtype, chúng ta thấy những gì có nghĩa là loại này:

State = String -> IO (String -> IO (String -> IO (String -> ... 

Phải mất một chuỗi, hiện một số I/O và yêu cầu một chuỗi khác vv

Đây là mã hóa yêu thích của tôi về mô hình lớp trừu tượng trong OO: abstract class -> type, subclasses -> các phần tử của kiểu đó.

Tuyên bố newtype State thay thế cho tuyên bố tóm tắt writeName và chữ ký của nó. Thay vì chuyển một số StateContext vào đó chúng tôi chỉ định một trạng thái mới, chúng tôi chỉ trả lại trạng thái mới.Việc nhúng giá trị trả lại trong IO cho biết rằng trạng thái mới được phép phụ thuộc vào I/O. Kể từ đó không phải là về mặt kỹ thuật cần thiết trong ví dụ này, chúng ta có thể sử dụng các loại nghiêm ngặt hơn

newtype State = State { unState :: String -> (State, IO()) } 

trong đó chúng ta vẫn có thể thể hiện tính toán này, nhưng trình tự của các quốc gia là cố định và không được phép phụ thuộc vào đầu vào. Nhưng hãy gắn bó với loại ban đầu, khoan dung hơn.

Và đối với những "khách hàng thử nghiệm":

runState :: State -> [String] -> IO() 
runState s [] = return() 
runState s (x:xs) = do 
    s' <- unState s x 
    runState s' xs 

testClientState :: IO() 
testClientState = runState stateA 
        [ "Monday" 
        , "Tuesday" 
        , "Wednesday" 
        , "Thursday" 
        , "Saturday" 
        , "Sunday" ] 
+0

P.S. Bạn sẽ cần phải nắm bắt các truy vấn toggling ngữ nghĩa là tốt. –

+0

@Don, oh, phải. hmm .... – luqui

+0

Đối với những gì nó có giá trị, tôi muốn nói phong cách mã hóa này là lý tưởng chỉ cho các lớp OO-idiomatic đúng đóng gói hành vi trừu tượng. Một số "lớp" bị cáo buộc trong mã OO bị cáo buộc là gần gũi hơn với bản dịch vụng về của phong cách Don đã sử dụng và do đó được hưởng lợi từ việc được quay trở lại những gì họ muốn ở nơi đầu tiên ... –

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