2011-06-19 36 views
8

Tôi đã từng chơi với các ngôn ngữ chức năng (đặc biệt là F #) và tôi thực sự thích toàn bộ khái niệm không thay đổi/khái niệm. Tuy nhiên, tôi là một chút bị mất về cách bạn đang giả sử để đại diện cho những thứ nhà nước trong các ngôn ngữ chức năng.đại diện cho những điều nhà nước trong các ngôn ngữ chức năng

Ví dụ: làm thế nào một người viết lại sau bằng ngôn ngữ chức năng? (Bất kỳ ngôn ngữ chức năng là tốt ... chỉ cần quấn quanh đầu tôi nó)

class state 
{ 
    int current_time; 
    bool is_completed() { 
     return current_time() - start_time > 30 seconds 
    } 
    double get_progress() { 
     return (current_time() - start_time)/30 seconds 
    } 
    void start() { 
     start_time = current_time(); 
    } 
} 
void main() { 
    state s; 
    s.start(); 
    while(s.is_completed() == false) { 
      print s.get_progress(); 
    } 
    print "finished"; 
} 
+0

Xem thêm http://stackoverflow.com/questions/5773070/how-are-mutable-arrays-implemented-in-haskell và http://stackoverflow.com/questions/tagged/haskell+monads –

Trả lời

8

dụ của bạn có chứa một vài điều mà sẽ làm việc khác nhau trong một ngôn ngữ chức năng:

  • lớp là có thể thay đổi - trong ngôn ngữ chức năng, bạn sẽ sử dụng một loại bất biến
  • bạn đang sử dụng current_time để có được thời gian hiện tại, nhưng điều này không phải là một hàm thuần túy (nó phụ thuộc vào một số trạng thái thay đổi toàn cục). Trong tinh khiết ngôn ngữ chức năng (Haskell), điều này là không được phép (và bạn phải sử dụng monads), nhưng hầu hết các ngôn ngữ chức năng không tinh khiết (F #, OCaml) cho phép điều này.
  • Chức năng main của bạn sử dụng vòng lặp thường không được khuyến khích bằng các ngôn ngữ chức năng (mặc dù một số hỗ trợ chúng).

Chiếc F # giải pháp thành ngữ sẽ đối phó với người đầu tiên và điểm cuối cùng như thế này:

let currentTime() = 
    System.DateTime.Now 

type State(startTime) = 
    static member Start() = 
    State(currentTime()) 
    member x.IsCompleted = 
    (currentTime() - startTime).TotalSeconds > 30.0 
    member x.Progress = 
    (currentTime() - startTime).TotalSeconds/30.0 

let main() = 
    let s = State.Start() 
    let rec loop() = 
    if not s.IsCompleted then 
     printf "%A" s.Progress 
     loop() 
    loop() 
    printf "finished" 

Loại State là bất di bất dịch theo nghĩa là nó không bao giờ thay đổi giá trị của trường địa phương. Nó không hoàn toàn là chức năng, bởi vì nó phụ thuộc vào thời gian hiện tại (thay đổi), nhưng đó không phải là một vấn đề trong F # (bạn chỉ cần phải nhận thức được điều đó).Nếu bạn cần một số phương pháp sửa đổi trạng thái (mà bạn không) thì phương thức sẽ trả về một cá thể mới là State (giống như .NET string).

Chức năng main được viết bằng cách sử dụng đệ quy thay vì vòng lặp - trong trường hợp này, nó không thực sự quan trọng (vòng lặp sẽ ổn trong F # quá). Điểm của việc sử dụng đệ quy là bạn có thể chuyển trạng thái hiện tại làm đối số và sử dụng một cá thể mới khi thực hiện một cuộc gọi đệ quy (mà về cơ bản thay đổi trạng thái hiện tại trong khi tính toán).

8

tôi là một chút mất vào cách bạn đang giả sử để đại diện cho điều stateful bằng các ngôn ngữ chức năng.

Cuối cùng, các máy tính mà chúng tôi thường sử dụng là những điều nhà nước. Ngôn ngữ lập trình phải đối phó với thực tế này ở một mức độ nào đó, hoặc bỏ qua một số khả năng của máy chủ của họ.

ngôn ngữ

FP đối phó với thực tế này bằng cách:

  • Cho phép bạn viết các chức năng mà phải mất tiểu bang, và tạo ra trạng thái mới (do đó làm cho các chức năng stateless)
  • Bao bì các khái niệm stateful trong một Monad (hoặc trong F #, a Computation Expression)

Đối với mã của bạn, bạn muốn xem xét tùy chọn đầu tiên. Viết lại các hàm của bạn để chấp nhận thời gian hiện tại làm đối số.

2

Tôi không biết nhiều về F #, nhưng từ những gì tôi hiểu, nó rất gần với OCaml. Đây là một số OCaml:

Loại bản ghi rất tốt ở đây. Dưới đây là một số mã tương đương trong OCaml:

#load "unix.cma" ;; 

type state = { start : float } ;; 

let mystate = { start = Unix.time() } in 
    let rec check() = 
     if Unix.time() -. mystate.start > 30. then 
      print_endline "finished" 
     else 
      check() 
    in 
     check() ;; 

(thời gian Unix là một phao trong OCaml đối với một số lý do, bạn có thể chuyển đổi sang một int32 nếu nó làm cho bạn cảm thấy tốt hơn.)

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