C#中的委托与F#中的第一类值有什么区别?

Ste*_*ger 27 c# f# delegates first-class-functions

更具体地说,代表具有作为F#中的第一类值的函数的特征(如果有的话)没有; 作为第一类值的特征有什么特征(如果有的话)在C#中委托没有?

Chr*_*ser 30

代表和F#"一流的功能价值"是完全不同的.

委托是CLR的一种机制,它是一个围绕函数指针+对象对的类型安全包装器(例如方法,this-pointer与方法地址一起被捕获).

另一方面,F#函数值是抽象类的实现FSharpFunc<,>(它曾经FastFunc<,>在F#正式发布之前调用).调用通过普通的虚方法发生,这比委托调用快得多.这就是F#-team首先不使用代表的原因.

因此,如果您可以通过抽象类/虚方法"实现"作为第一类值的函数,为什么Microsoft会添加委托?

  • 没有其他选择在.NET 1.0/1.1中,没有泛型,因此您必须为要使用的每个函数签名定义新的委托类型(="函数类型").
  • (不,只是使用Java中的接口不计算.:-P)

好的,但是从.NET 2.0开始我们有Generics,为什么我们还有代表呢?为什么我们不能只使用Func<,>Action<>一切?

  • 向后兼容性
  • 多播代理可以将代理链接在一起以形成新的代理.此机制用于在VB.NET和C#中实现事件.在幕后,一个事件实际上只是一个代表字段.使用+=语法,您实际上将事件处理程序委托添加到事件字段中的委托链.

除了活动,是否有理由使用代表 FSharpFunc<,>

是的,一个:FSharpFunc<,>包括lambda表达式*的每个实现都是一个新类.在.NET中,类编译在已编译程序集的元数据中.另一方面,代表不需要额外的元数据.委托类型可以,但实例化这些委托类型在元数据方面是免费的.

但是等等,C#lambda-expressions /匿名方法是否也被实现为隐藏类?

是的,C#lambdas占据了两个世界中最糟糕的^^

  • 在C#3.0中,它现在非常接近.在2.0中,代表是如此繁琐(非常繁重的语法),你很少使用它们.而F#类型的推理也有帮助.也就是说,我试图提出的观点是"语法糖的优势"导致范式转换.请参阅http://stackoverflow.com/questions/196294/what-is-a-catamorphism-and-can-it-be-implemented-in-c-3-0/196451#196451作为此证据. (2认同)
  • @SealedSun:在以一般方式支持适当的高级函数操作(组合等)之前,无法将C#称为FP语言.就像我喜欢模式匹配和简单的不变性一样,它们 - 严格来说 - 并不是FP的关键. (2认同)
  • @pblasucci函数组合,const和flip之类的东西只是库函数.它们是FSharp运行时库形式的.NET 4.0的一部分.但实际上缺少的是自动currying和partial.application的一个很好的语法. (2认同)

thr*_*thr 6

我只是想补充一点,来自SealedSun的这句话并非如此:

调用通过普通的虚方法发生,这比委托调用快得多.这就是F#-team首先不使用代表的原因.

F#函数并不比委托调用快,可能是.NET 1.0中的情况,但现在委托调用和调用虚拟方法几乎相当.

与调用委托相比,调用编译器静态绑定的F#函数也非常慢.

open System
open System.Diagnostics

let time name f = 
  let sw = new Stopwatch()
  sw.Start()
  f()
  sw.Stop()
  printfn "%s: %dms" name sw.ElapsedMilliseconds

time "delegate call" (
  fun () ->
    let f = 
      new Func<int, int, int>(
        fun i1 i2 -> 
          let y = i1 + i2
          let x = y + i1
          let z = x + y + i2
          z + x + y + i1
      )

    let mutable r = 0
    for i = 0 to 10000000 do
      r <- f.Invoke(i, i)
)

let f i1 i2 = 
  let y = i1 + i2
  let x = y + i1
  let z = x + y + i2
  z + x + y + i1

time "fsharp func (static bound)" (
  fun () ->
    let mutable r = 0
    for i = 0 to 10000000 do
      r <- f i i
)

let make f =
  let mutable r = 0
  for i = 0 to 10000000 do
    r <- f i i

time "fsharp func (dynamic bound)" (
  fun () -> make f
)

Console.ReadLine() |> ignore
Run Code Online (Sandbox Code Playgroud)

在我的计算机上生成以下结果

delegate call: 65ms
fsharp func (staticly linked): 4ms
fsharp func (dynamic invoke): 356ms
Run Code Online (Sandbox Code Playgroud)