【问题标题】:F#: Storing and mapping a list of functionsF#:存储和映射函数列表
【发布时间】:2010-12-19 06:54:49
【问题描述】:

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

例如:

事件 1:在屏幕上显示一些文本 N 帧并播放声音效果

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

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

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

如果这是一个好的解决方案,我可能会在 C++ 或 C# 中完成。我的目标是在 F# 中做一个等效或更好的解决方案。

【问题讨论】:

  • 你想用你的函数列表解决什么问题?
  • 我改变了我原来的问题,因为它是在解决方案空间中定义的;不是问题空间。我希望这可以解决问题。

标签: list function f# map


【解决方案1】:

我已经阅读了您的问题两次,但仍然不确定我是否完全理解您想要什么。但据我了解,您的“事件”不一定按照它们在“列表”中出现的顺序被调用。如果是这种情况,您实际上并不需要 F# 列表,而是需要某种查找。

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

编辑

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

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

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

不确定这是否有帮助:我认为您必须尝试重新表述您的问题,从这里答案的多样性来看。

【讨论】:

    【解决方案2】:

    您似乎正在尝试以非常复杂的方式做某事。这有时是必要的,但通常不是。

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

    【讨论】:

    • 这不是答案,而是评论
    【解决方案3】:

    你的意思是这样的吗?

    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 用于解决一个模棱两可的问题!
    【解决方案4】:

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

    List<`a->`b>
    

    这假定函数采用单个参数。

    但是,您正在尝试找出类型的语法这一事实暗示您仍在看待这一点,就好像您正在使用过程语言进行编码一样。

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

    【讨论】:

      【解决方案5】:

      不太确定您要在这里实现什么...仔细考虑您正在寻找的确切类型可能会有所帮助。听起来您可能想通过首先应用每个函数将(unit-&gt;(unit-&gt;unit)) list 映射到(unit-&gt;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”。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-27
      • 2021-11-17
      • 1970-01-01
      相关资源
      最近更新 更多