用函数式语言表示有状态的事物
我一直在尝试函数式语言(特别是 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您的示例包含一些在函数式语言中工作方式不同的内容:
current_time
来获取当前时间,但是这个不是一个纯函数(它取决于某些全局变化状态)。在纯函数式语言(Haskell)中,这是不允许的(并且您必须使用 monad),但大多数非纯函数式语言(F#、OCaml)允许这样做。main
函数使用循环 - 在函数式语言中通常不鼓励使用循环(尽管有些语言支持循环)。惯用的 F# 解决方案将像这样处理第一点和最后一点:
State
类型是不可变的,因为它永远不会更改其本地字段的值。它不纯粹是函数式的,因为它取决于(变化的)当前时间,但这在 F# 中不是问题(您只需意识到这一点)。如果您需要某种修改状态的方法(您不需要),那么该方法将返回State
的新实例(就像 .NETstring
)。main
函数是使用递归而不是循环编写的 - 在这种情况下,这并不重要(在 F# 中循环也可以)。使用递归的要点是,您可以将当前状态作为参数传递,并在进行递归调用时使用新实例(这实际上会在计算过程中更改当前状态)。Your example contains a few things that would work differently in a functional language:
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.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:
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 ofState
(just like .NETstring
).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).最终,我们常用的计算机都是有状态的东西。编程语言必须在某种程度上应对这一事实,或者放弃其主机的一些功能。
FP 语言通过以下任一方式处理此事实:
至于您的代码,您需要查看第一个这些选项。重写您的函数以接受当前时间作为参数。
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:
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.
我对F#了解不多,但据我了解,它与OCaml非常接近。这里有一些 OCaml:
记录类型非常擅长于此。下面是 OCaml 中的一些等效代码:(
出于某种原因,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:
(Unix time is a float in OCaml for some reason; you could convert to an int32 if it makes you feel better.)