如果我定义一个简单的函数:
let myConcat a b =
a + "+" + b
然后,假设函数是F#中的第一类值,我希望能够像这样使用myConcat
:
let result = myConcat "a" (fun () -> "b")
它不会产生字符串“a + b”,而是给出了以下错误:
error FS0002: This function takes too many arguments, or is used in a context where a function is not expected
希望我只是弄错了语法,但在我看来,函数不能真正用作F#中的值。谁能解释一下这里发生了什么?
修改 为了进一步澄清我的要求,我可以使用等效的C#代码:
public string myConcat(string a, string b) { return a + "+" + b; }
如果我想在参数b中传递“稍后调用函数”,我必须这样做:
public string myConcat(string a, Action<string> b) { return a + "+" + b(); }
或者我可以这么称呼它:
Func<string> b = () => "b";
var result = myConcat("a", b());
C#不(据我所知)声称函数是一等值。 F#确实提出了这个主张。那么当我不能对待一个单位时有什么区别 - &gt; string函数作为“延迟求值”字符串值?
答案 0 :(得分:6)
您正在创建的lambda具有type(unit - &gt; string)。然后,您尝试拨打电话
string - &gt; string - &gt; (单位 - &gt;字符串) - &gt;串
当预期的通话应具有类型
时string - &gt; string - &gt; string - &gt;串
所以,你试图传入lambda,当你真正要传入的是调用lambda的结果时
let result = myConcat "a" ((fun() -> "b")())
答案 1 :(得分:4)
你可以这样称呼它:let result = myConcat "a" ((fun() -> "b")())
创建myConcat时,它被解释为:val myConcat : a:string -> b:string -> string
它期望第二个参数作为字符串,并且您传递一个方法。
要做你想做的事,你必须将myConcat声明为let myConcat a b = a + "+" + b()
,然后你可以传递一个函数作为第二个参数。
然后将其解释为val myConcat : a:string -> b:(unit -> string) -> string
答案 2 :(得分:2)
主要感谢Mauricio Scheffer,我对我的问题有了答案:
C#和许多其他语言也提供“功能是一流的价值”。但是,作为OO语言,在C#中,这通常表示为“函数是一等对象”。短语“函数是第一类值”只是指通过参数将函数引用传递给另一个函数的能力,就好像它是一个值一样。没有“魔术”解释例如单位 - &gt;字符串值等同于正在进行的字符串值,它只是一个单位 - &gt; string函数是传递给另一个值的有效值。
由于F#强大的类型推断功能,我不需要指定单位 - &gt; F#中引用函数的字符串类型,就像我使用C#一样,但是编译器会推断出这种类型,因此我不能只传入一个简单的字符串而不将其包装在一个匿名单元中 - &gt;首先是字符串函数。
如果您比我理解这些东西并且我遇到了问题,请进行编辑以纠正错误。