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

3
我有一些在游戏中发生的事件,我想控制这些事件发生的时间和顺序。
例如:
事件1:在屏幕上显示N帧文本并播放声音效果
事件2:清除屏幕上的文本
我的解决方案(也许有更好的)是拥有一个包含事件的函数列表。事件执行它们的行为,然后返回下一个要发生的事件。我考虑使用List.map或List.collect,因为我实际上是将一个事件列表映射到一个新的事件列表,同时执行一些行为代码。
在上面的示例中,事件1可以由两个函数组成:一个显示文本,一个播放声音(因此需要一个列表)。显示文本的函数将返回自己的副本,以便在N-1帧中重复显示文本,然后返回清除文本的Event2。播放声音的函数将返回相当于no-op的内容。
如果这是一个好的解决方案,我可能可以在C++或C#中实现它。我的目标是在F#中实现等效或更好的解决方案。

你的函数列表是为了解决什么问题? - Jørgen Fogh
我已经修改了我的原始问题,因为它是在解决方案空间中定义的,而不是问题空间中。我希望这能澄清事情。 - rysama
5个回答

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# 交互):

> 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 = ()
> 

**编辑:** 如果您希望能够添加操作,也许最好制作一个使用队列内部的操作分发器,因为用列表附加是O(N),而用队列是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 因为你在一个模糊的问题上付出了努力! - Benjol

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

我的目标是将函数调用链接在一起。例如,函数“foo”将返回下一个要调用的函数“bar”。 - rysama

2

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

List<`a->`b>

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

但是,你试图弄清楚类型的语法这一事实表明,你仍然把它看作是在编写过程式语言的代码。

“函数式”处理方式是专注于生成列表的逻辑,并让编译器根据你的代码推断类型。


1

我已经读了你的问题两次,但仍然不确定我是否完全理解你想要的。但是从我的理解来看,你的“events”并不一定按照它们在“list”中出现的顺序被调用。如果是这种情况,那么你不需要一个 F# 列表,而是需要某种查找。

另一个问题是,事件是否真的能够确定它之后应该发生什么?这有点像硬编码你的功能,不是吗?

编辑

我在评论中看到你说你想要“将函数调用链接在一起”。

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

如果你想更加函数化一些,你可以使用 continuation - 每个函数都需要一个额外的参数,即下一个要执行的函数。几乎是单子(我相信),只是在你的情况下它们似乎是动作,所以没有值需要从一个函数传递到下一个函数。

不确定这是否有所帮助:根据这里回答的多样性,我认为你需要尝试重新表达你的问题。


0

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

既然你在问这个问题,我假设你在命令式语言方面有更多的经验。似乎你问题的真正解决方案与函数列表完全不同。


这不是一个答案,这是一条评论。 - Frames Catherine White

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接