开发者

represent stateful things in functional languages

I've been playing around with functional languages (F# in particular) and am really liking the whole immutable/concept. However, I'm a bit lost on how you're suppose to represent stateful things in functional languages.

For example, how would one rewrite the following in a functional language? (any functional language is fine... just need to wrap my head around it)

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 "fin开发者_开发百科ished";
}


Your example contains a few things that would work differently in a functional language:

  • The class is mutable - in functional languages, you would use an immutable type
  • You're using current_time to get the current time, but this is not a pure function (it depends on some global changing state). In pure functional languages (Haskell), this is not allowed (and you have to use monads), but most of the impure functional languages (F#, OCaml) allow this.
  • Your main function uses a loop - loops are generally discouraged in functional languages (although some support them).

The idiomatic F# solution would deal with the first and the last point like this:

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"

The type State is immutable in the sense that it never changes the value of its local field. It is not purely functional, because it depends on the (changing) current time, but that's not a problem in F# (you just have to be aware of that). If you needed some method that modifies the state (which you don't) then the method would return a new instance of State (just like .NET string).

The main function is written using recursion instead of a loop - in this case, it doesn't really matter (loop would be fine in F# too). The point of using a recursion is that you could pass the current state as an argument and use a new instance when making a recursive call (which essentially changes the current state during the computation).


I'm a bit lost on how you're suppose to represent stateful things in functional languages.

Ultimately, the computers we commonly use are stateful things. Programming languages have to cope with this fact at some level, or forego some of the abilities of their host computer.

FP languages deal with this fact by either:

  • Allowing you to write functions that take state, and produce new state (therefore making the function stateless)
  • Wrapping the stateful concept in a Monad (or in F#, a Computation Expression)

As for your code, you'd want to look at the first of these options. Rewrite your functions to accept the current time as an argument.


I don't know much about F#, but from what I understand, it's very close to OCaml. So here's some OCaml:

Record types are very good at this. Here's some equivalent code in 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 () ;;

(Unix time is a float in OCaml for some reason; you could convert to an int32 if it makes you feel better.)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜