【问题标题】:Call a function from its name as a string in f#在 f# 中从函数的名称作为字符串调用函数
【发布时间】:2011-06-03 21:27:34
【问题描述】:

我认为我可以通过引用来做到这一点 - 但我不知道如何。

我应该只使用带有名称的函数表 - 还是他们这样做的一种方式?

谢谢。

更多信息......

我从 excel 中调用了很多 f# 函数,我想知道我是否可以编写一个 f# 函数

让 fs_wrapper (f_name:string) (f_params:list double) = 此位使用 f_params 调用 fname

然后使用

=fs_wrapper("my_func", 3.14, 2.71)

在工作表中,而不是单独包装所有功能。

【问题讨论】:

  • 你能多展示一些你正在尝试做的事情吗?

标签: f# quotations


【解决方案1】:

您需要使用标准的 .NET 反射来执行此操作。引用不会有帮助,因为它们表示使用标准 .NET MethodInfo 的函数调用,因此无论如何您都需要使用反射。引用的唯一好处(与幼稚的反射相比)是您可以编译它们,这可以为您提供更好的性能(但编译并不完美)。

根据您的具体情况(例如,函数的位置),您必须执行以下操作:

module Functions =
  let sin x = sin(x)
  let sqrt y = sqrt(y)

open System.Reflection

let moduleInfo = 
  Assembly.GetExecutingAssembly().GetTypes()
  |> Seq.find (fun t -> t.Name = "Functions")

let name = "sin"
moduleInfo.GetMethod(name).Invoke(null, [| box 3.1415 |])

除非您需要一些可扩展性或拥有大量函数,否则使用包含字符串作为键和函数值作为值的字典可能是一个更简单的选择:

let funcs = 
  dict [ "sin", Functions.sin;
         "sqrt", Functions.sqrt ]

funcs.[name](3.1415)

【讨论】:

  • 谢谢,这很好用。我也可以将模块名称作为字符串传递。接下来是参数类型管理,但我会暂时搁置这个。 “盒子”是干什么用的?
  • @b1g3ar5 - Invoke 方法将参数作为对象数组 (obj[]),因为它无法知道参数的实际类型。 box 操作将 float 值运行到 obj 值中。 [| 3.14 |] 的类型将是 float[],这与预期的类型不匹配。
  • 所有这些语法废话让我想念 Python/Ruby。如果你有的话,即使是动态的 C#。
  • @GregC - 如果您愿意,可以使用 F# 动态运算符 ? 并编写类似 funcs?sin(3.14) 的内容。当然,所有这些语法等等都可以隐藏在一个简单的函数中。
  • 有任何理由使用GetTypes 并枚举结果,而不是使用GetType
【解决方案2】:

有很多方法,但一种方法是使用反射,例如:

typeof<int>.GetMethod("ToString", System.Type.EmptyTypes).Invoke(1, null)
typeof<int>.GetMethod("Parse", [|typeof<string>|]).Invoke(null, [|"112"|])

GetMethod 可以选择采用定义签名的类型数组,但如果您的方法明确,则可以跳过它。

【讨论】:

    【解决方案3】:

    继续了解 Thomas 所暗示的内容,请查看 Matthew Podwysocki 的 Using and Abusing the F# Dynamic Lookup Operator。它为在 F# 中进行动态查找提供了一种语法简洁的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 2018-08-22
      • 2019-11-23
      • 2020-08-03
      • 2011-12-17
      相关资源
      最近更新 更多