F#:存储和映射函数列表

时间:2009-11-22 20:21:55

标签: list function f# map

我在游戏中发生了很多事件。我想控制这些事件发生的时间和顺序。

例如:

事件1:在屏幕上显示N帧的一些文字&发挥音效

事件2:清除屏幕上的文字

我的解决方案(可能有一个更好的解决方案)是拥有包含事件的函数列表。事件执行其行为然后返回在游戏中发生的下一个事件。我想过使用List.map或List.collect,因为我实际上是在执行某些行为代码时将事件列表映射到新的事件列表。

在上面的示例中,Event1可以由两个函数组成:一个显示文本,另一个播放声音(因此需要列表)。显示文本的函数将为N-1帧返回自身的副本,然后它将返回清除文本的Event2。播放声音功能将返回相当于无操作的声音。

如果这是一个很好的解决方案,我可以用C ++或C#来做。我的目标是在F#中做同等或更好的解决方案。

5 个答案:

答案 0 :(得分:5)

你的意思是这样吗?

let myActions =
    [fun () -> printfn "You've woken up a dragon."
     fun () -> printfn "You hit the dragon for 0 points of damage."
     fun () -> printfn "The dragon belches."
     fun () -> printfn "You have died."] 

let actionBuilder actionList = 
    let actions = ref actionList
    fun () ->
        match !actions with
        | [] -> ()
        | h::t -> h(); actions := t

用法(F#interactive):

> let doSomething = actionBuilder myActions;;

val doSomething : (unit -> unit)

> doSomething();;
You've woken up a dragon.
val it : unit = ()
> doSomething();;
You hit the dragon for 0 points of damage.
val it : unit = ()
> doSomething();;
The dragon belches.
val it : unit = ()
> doSomething();;
You have died.
val it : unit = ()
> doSomething();;
val it : unit = ()
> 

**编辑:**如果你想能够添加动作,也许最好制作一个内部使用Queue的动作分配器,因为追加是带有列表的O(N)和带有一个O的O(1)队列:

type actionGenerator(myActions: (unit->unit) list) =
    let Q = new System.Collections.Generic.Queue<_>(Seq.ofList myActions)

    member g.NextAction = 
        fun () -> 
            if Q.Count = 0 then ()
            else Q.Dequeue()()

    member g.AddAction(action) = Q.Enqueue(action)

答案 1 :(得分:2)

不太确定你在这里想要实现的目标......想一想你正在寻找的确切类型会很有帮助。听起来您可能希望通过应用第一个中的每个函数将(unit->(unit->unit)) list映射到(unit->unit) list。如果是这种情况,你可以这样做:

let l = [(fun () -> (fun () -> printfn "first nested fn")); (fun () -> (fun () -> printfn "second nested fn"))]
let l' = List.map (fun f -> f()) l

答案 2 :(得分:2)

如果您正在寻找声明列表类型的语法,那么这是一种方法:

List<`a->`b>

这假设该函数只接受一个参数。

但是你试图找出该类型的语法这一事实暗示你仍然在看这个,就好像你是用过程语言编写的那样。

这样做的“功能”方法是专注于生成列表的逻辑,让编译器根据您的代码推断出类型

答案 3 :(得分:1)

我已经两次阅读你的问题了,我仍然不确定我到底知道你想要什么。但根据我的理解,您的“事件”不一定按照它们出现在“列表”中的顺序调用。如果是这种情况,你真的不想要一个F#列表,你想要某种查找。

现在另一个问题是,一个事件确定应该遵循什么才是真的好主意?这类似于一劳永逸地对您的功能进行硬编码,不是吗?

修改

我在评论中看到你说你想'将函数调用连在一起'。

一个接一个地写它们怎么样?毕竟我们不在Haskell中,F#会按照你编写它们的顺序触发它们。

如果你想要更具功能性,可以使用continuation - 每个函数都需要一个额外的参数,这是下一个要执行的函数。几乎是monadic(我相信),除了在你的情况下它们似乎是动作,所以没有值从一个函数到下一个函数串起来。

不确定这是否有帮助:我认为你必须尝试改写你的问题,从答案的多样性来判断。

答案 4 :(得分:0)

看起来你正试图以一种非常复杂的方式做某事。这有时是必要的,但通常不是。

由于您提出这个问题,我认为您在命令式语言方面有更多经验。似乎问题的真正的解决方案与功能列表完全不同。