Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
功能反应F#-在游戏中存储状态_F#_Functional Programming_State_Frp - Fatal编程技术网

功能反应F#-在游戏中存储状态

功能反应F#-在游戏中存储状态,f#,functional-programming,state,frp,F#,Functional Programming,State,Frp,我是一名学生,目前正在使用F#学习功能反应范式。这对我来说是全新的观点。昨天我学习了如何使用这个范例创建一个简单的乒乓球游戏。到目前为止,我所理解的想法是:我们认为价值是时间的函数。就其纯形式而言,它是无状态的。但是,我需要记住球的位置(或状态)。所以我总是传递球的当前位置作为全局函数的参数 如果我们谈论稍微复杂一些的游戏,比如《太空入侵者》,我们有很多状态(外星人的位置、外星人当前的生命、剩余炸弹的数量等等) 有没有解决这个问题的优雅/最佳方法?我们总是在顶层存储状态吗?是否所有当前状态都应作

我是一名学生,目前正在使用F#学习功能反应范式。这对我来说是全新的观点。昨天我学习了如何使用这个范例创建一个简单的乒乓球游戏。到目前为止,我所理解的想法是:我们认为价值是时间的函数。就其纯形式而言,它是无状态的。但是,我需要记住球的位置(或状态)。所以我总是传递球的当前位置作为全局函数的参数

如果我们谈论稍微复杂一些的游戏,比如《太空入侵者》,我们有很多状态(外星人的位置、外星人当前的生命、剩余炸弹的数量等等)

有没有解决这个问题的优雅/最佳方法?我们总是在顶层存储状态吗?是否所有当前状态都应作为全局函数的附加输入参数

有人能用F#上的简单例子来解释这一点吗?
非常感谢。

我对F#下的反应式编程没有任何经验,但是纯函数系统中的全局状态问题非常常见,并且有一个非常优雅的解决方案:Monads

虽然单子本身主要用于Haskell,但其基本概念使其成为F#as

这样做的目的是,您实际上不会更改状态,而只是描述状态的转换,即如何生成新状态。状态本身可以完全隐藏在程序中。通过使用特殊的一元语法,您几乎可以强制编写纯但有状态的程序

从中获取一个(修改过的)实现,
状态
monad可能如下所示

let (>>=) x f =
   (fun s0 ->
      let a,s = x s0    
      f a s)       
let returnS a = (fun s -> a, s)

type StateBuilder() =
  member m.Delay(f) = f()
  member m.Bind(x, f) = x >>= f
  member m.Return a = returnS a
  member m.ReturnFrom(f) = f

let state = new StateBuilder()     

let getState = (fun s -> s, s)
let setState s = (fun _ -> (),s) 

let runState m s = m s |> fst
让我们举个例子:我们想编写一个函数,在继续操作时可以将值写入日志(只是一个列表)。因此,我们定义

let writeLog x = state {
  let! oldLog = getState // Notice the ! for monadic computations (i.e. where the state is involved)
  do! setState (oldLog @ [x]) // Set new state
  return () // Just return (), we only update the state
}
state
中,我们现在可以在命令式语法中使用它,而无需手动处理日志列表

let test = state {
   let k = 42
   do! writeLog k // It's just that - no log list we had to handle explicitly
   let b = 2 * k
   do! writeLog b
   return "Blub"
}

let (result, finalState) = test [] // Run the stateful computation (starting with an empty list)
printfn "Result: %A\nState: %A" result finalState

不过,这里的一切都是纯功能性的;)

托马斯在F#中给出了一个关于反应式编程的例子。许多概念应该适用于您的案例。

进行FRP的方法不止一种,这是一个活跃的研究领域。什么是最好的在很大程度上取决于事物如何相互作用的细节,未来可能会出现新的更好的技术

广义上,我们的想法是让行为成为时间的函数,而不是普通的价值观(如你所说)。行为可以根据其他行为定义,并且可以定义为在特定事件发生时在其他行为之间交换

在您的示例中,您通常不需要通过参数来记住球的位置(但对于某些类型的FRP,您可以这样做)。相反,你可以有一种行为:
ballPos:time->(float*float)

这可能有全局作用域,或者对于一个更大的程序,最好有一个本地作用域,在该作用域中使用它

随着事情变得越来越复杂,您将以越来越复杂的方式定义行为,这取决于其他行为和事件,包括在不同FRP框架中处理不同的递归依赖关系。在F#中,对于递归依赖,我希望您需要一个
let rec
,包括所有涉及的行为。但这些仍然可以组织成结构-在顶层,您可能有:

type alienInfo =  { pos : float*float; hp : float }
type playerInfo = { pos : float*float; bombs : int } 
let rec aliens : time -> alienInfo array =             // You might want laziness here.
    let behaviours = [| for n in 1..numAliens -> 
                        (alienPos player n, alienHP player n) |]
    fun t -> [| for (posBeh, hpBeh) in behaviours -> 
                {pos=posBeh t; hp=hpBeh t} |]          // You might want laziness here.
and player : time -> playerInfo  = fun t ->
    { pos=playerPos aliens t; bombs=playerBombs aliens t}
然后,alienPos,alienHP的行为可以定义为依赖于玩家,playerPos,playerBombs的行为可以定义为依赖于外星人


无论如何,如果你能提供更多关于你正在使用哪种玻璃钢的细节,那么就更容易给出更具体的建议。(如果你想要什么样的建议-我个人建议阅读:)

也许你会想看看。

是一种现代FRP实现。对于在游戏(如《太空入侵者》)中无处不在的动态集合建模,它包含基于箭头化FRP概念的。你一定要去看看。

这主要是关于状态单子的。函数式反应式编程通常涉及单子,但通常不涉及这种简单的状态单子。正如我所说,我没有FRP方面的经验。尽管如此,状态monad(或者完全是monad)似乎是人们要求的概念——方便地存储和修改上下文数据,而不会失去引用的透明度。如果FTP已经使用了一元基础设施,那就更好了。一个状态单变量转换器应该可以实现这一点(你是说简单类型的吗?)。但如果没有解释基本原理,这些信息将毫无用处!FRP的要点是允许将行为定义为时间的连续函数-例如,可以将球在重力作用下的z位置定义为z(t)=9.8*t*t。一元状态仅与进行离散更改的状态相关-FRP中也允许离散更改,但它们不太集中,并且通常不符合单子的确切形式。@RD1:很有趣,谢谢。但是,大多数与用户输入相关联的操作不是本质上是离散的吗?即使没有-为一个球定义一个连续的世界函数很简单,但如果系统稍微复杂一些(更多的球),这不都归结为求解(即积分)微分方程吗?鼠标的实际位置是一个连续变量,在FRP中是这样处理的。当然,可用的位置数据仅采样并近似于实际位置,但无论如何,这在FRP中到处都会发生,如果鼠标位置用于控制屏幕上或游戏中某物的位置,则将其视为时间的连续函数是非常自然的。微分方程在某些方法中是相关的,但不是必要的。我不是专家,请看:函数式反应式编程不仅仅是函数式语言中的反应式编程。主要技术是将行为表示为时间的函数。这些行为可能相互依赖,也可能取决于事件