用函数式语言表示有状态的事物

发布于 2024-11-16 00:37:43 字数 580 浏览 0 评论 0原文

我一直在尝试函数式语言(特别是 F#),并且非常喜欢整个不可变/概念。然而,我对如何用函数语言表示有状态的事物有点迷失。

例如,如何用函数式语言重写以下内容? (任何函数式语言都可以......只需要我的头脑围绕它)

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";
}

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 "finished";
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

浪漫之都 2024-11-23 00:37:43

您的示例包含一些在函数式语言中工作方式不同的内容:

  • 该类是可变的 - 在函数式语言中,您将使用不可变类型
  • 您正在使用 current_time 来获取当前时间,但是这个不是一个纯函数(它取决于某些全局变化状态)。在纯函数式语言(Haskell)中,这是不允许的(并且您必须使用 monad),但大多数非纯函数式语言(F#、OCaml)允许这样做。
  • 您的 main 函数使用循环 - 在函数式语言中通常不鼓励使用循环(尽管有些语言支持循环)。

惯用的 F# 解决方案将像这样处理第一点和最后一点:

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"

State 类型是不可变的,因为它永远不会更改其本地字段的值。它不纯粹是函数式的,因为它取决于(变化的)当前时间,但这在 F# 中不是问题(您只需意识到这一点)。如果您需要某种修改状态的方法(您不需要),那么该方法将返回 State 的新实例(就像 .NET string)。

main 函数是使用递归而不是循环编写的 - 在这种情况下,这并不重要(在 F# 中循环也可以)。使用递归的要点是,您可以将当前状态作为参数传递,并在进行递归调用时使用新实例(这实际上会在计算过程中更改当前状态)。

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).

池予 2024-11-23 00:37:43

我对如何用函数式语言表示有状态的事物有点迷惑。

最终,我们常用的计算机都是有状态的东西。编程语言必须在某种程度上应对这一事实,或者放弃其主机的一些功能。

FP 语言通过以下任一方式处理此事实:

  • 允许您编写获取状态的函数并生成新状态(因此使函数无状态)
  • 将有状态概念包装在 Monad (或在 F# 中,计算表达式

至于您的代码,您需要查看第一个这些选项。重写您的函数以接受当前时间作为参数。

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.

半透明的墙 2024-11-23 00:37:43

我对F#了解不多,但据我了解,它与OCaml非常接近。这里有一些 OCaml:

记录类型非常擅长于此。下面是 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 时间在 OCaml 中是浮点型;如果您感觉更好,可以转换为 int32。)

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.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文