Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么F#中的函数会以这种方式实现?_F# - Fatal编程技术网

为什么F#中的函数会以这种方式实现?

为什么F#中的函数会以这种方式实现?,f#,F#,F#函数与普通的CLR方法有很大的不同,这是因为当前支持。例如函数 let inc a = a + 1 将具有类型Microsoft.FSharp.Core.FSharpFunc。它在C#互操作性方面产生了问题。函数必须经过专门设计,以便于从C#调用 这种设计背后的基本原理是什么?我认为原因在于讨好支持。但是咖喱可以使用闭包实现。例如,此代码: let add a b = a + b let inc = add 1 可通过编译器轻松转换为: let add a b = a + b let i

F#函数与普通的CLR方法有很大的不同,这是因为当前支持。例如函数

let inc a = a + 1
将具有类型Microsoft.FSharp.Core.FSharpFunc。它在C#互操作性方面产生了问题。函数必须经过专门设计,以便于从C#调用

这种设计背后的基本原理是什么?我认为原因在于讨好支持。但是咖喱可以使用闭包实现。例如,此代码:

let add a b = a + b
let inc = add 1
可通过编译器轻松转换为:

let add a b = a + b
let inc = fun x -> add 1 + x

在这种情况下,add和inc都可以是普通的
System.Func
对象。我相信这一设计决策背后有一些有趣的原因。

据我记忆所及,在F#中为函数使用单独类型的动机是性能(在早期版本中,FSharpFunc实际上被称为
FastFunc
)。我不完全确定最近的进展(我确定F#团队做了一些测试,以确定学员是否会在Visual Studio 2010中工作),但以下是我对问题的理解:

如果您有一个函数
add:int->int->int
,那么该函数可以表示为委托
Func
(使用当前表示法)。问题是,您经常希望使用两个参数调用它,如
add1 2

使用嵌套
Func
类型的表示,这将编译为
add.Invoke(1).Invoke(2)

但是,当编译像
add
这样的函数时,F#编译器实际上会创建一个新类,比如说,
AddClass
,它继承自
FSharpFunc
,并添加一个附加的
调用
重载和两个参数。这意味着,在大多数情况下,
add12
可以编译为一个调用
add.Invoke(1,2)

这种设计使F#代码更快。它稍微使互操作性复杂化,但不会太复杂。编写接受委托的F#成员或函数相当容易:

let foo (inc : Func<int, int>) = inc.Invoke(41)
让foo(inc:Func)=inc.Invoke(41)

(您只需添加类型注释,然后调用
f.Invoke
——但也可以将
f.Inokve
用作一级值并将其传递给其他函数)

我猜F#表示法支持大步语义,而
System.Func
不支持。

与C#交互的最佳方法是将所有内容包装在类/成员中。C#永远不必查看成员的内部工作。

你可能会更幸运地给Don Syme/F#团队的其他人发电子邮件。虽然我有理由相信整个原因都是为了讨好,但对于更复杂的情况来说,这可能不是那么简单。我相信Don Syme和其他F#团队成员也是如此。Don Syme不是,但Tomas Petricek是,Brian也是F#团队的一员(我想)@JohnPalmer我很确定Keith B.也在这里。同样值得注意的是F#支持针对.NET 2.0,但是
System.Func
System.Action
仅在.NET 3.5.Wow中介绍,这是非常有趣的实现细节。谢谢F#函数更快的另一个原因是:CLI操作/函数继承自System.MulticastDelegate。它们在被调用时迭代一个内部调用列表,而F#函数则不会。什么是“大步语义”?我猜这是某种函数聚合,编译器可以从较小的函数创建较大的函数。是吗?是的。您不希望每次应用另一个咖喱参数时都创建临时闭包,这样您就可以发现何时可以同时应用多个咖喱参数并跳过临时参数,从而迈出“一大步”。OCaml普及了这一点,而标准ML则倾向于避免套用。