我对如何将函数标记为泛型而没有明确的类型声明(如let add a b = a + b
val add : a:int -> b:int -> int
这给了我们
add "Hello " "World!"
然而,我们可以立即致电
val add : a:string -> b:string -> string
val it : string = "Hello World!"
现在add的值是
add 2 3 // then we get
error: This expression was expected to have type string but here has type int
如果我们再打电话
(+)
如何确保函数适用于所有已定义函数{{1}}的类型
答案 0 :(得分:18)
这是F#在壁橱里令人尴尬的骷髅。
试试这个:
> let mapPair f (x,y) = (f x, f y)
val mapPair : f:('a -> 'b) -> x:'a * y:'a -> 'b * 'b
完全通用!显然,功能应用和元组工作。
现在试试这个:
> let makeList a b = [a;b]
val makeList : a:'a -> b:'a -> 'a list
嗯,也是通用的。怎么样:
> let makeList a b = [a + b]
val makeList : a:int -> b:int -> int list
啊哈,只要我有一个(+)
,就会因某种原因变成int
。
让我们继续玩:
> let inline makeList a b = [a + b]
val inline makeList :
a: ^a -> b: ^b -> ^c list
when ( ^a or ^b) : (static member ( + ) : ^a * ^b -> ^c)
嗯,有趣。事实证明,如果我创建函数inline
,那么F#确实认为它是通用的,但它也给它这个奇怪的when
子句,并且我的泛型参数有这个奇怪的{ {1}}符号而不是通常的刻度。^
要求其参数定义(+)
。我们来验证:
static member (+)
现在,问题在于CLR不支持这种通用参数(即"任何类型,只要它有这样的成员"),所以F#必须伪造并在编译时解析这些调用。但正因为如此,使用此功能的任何方法都无法编译为真正的通用IL方法,因此必须是单态的(由> let x = 0 :> obj
let y = 0 :> obj
let z = x + y
Script1.fsx(14,13): error FS0001: The type 'obj' does not support the operator '+'
> type My() =
static member (+)( a:My, b:My ) = My()
let x = My()
let y = My()
let z = x + y
val x : My
val y : My
val z : My
启用)。
但是,要求使用算术运算符的每个函数都被声明为inline
,这不是很不方便吗?因此,F#又采取了另一个步骤,并尝试根据它们在代码中稍后实例化的方式来修复这些静态解析的泛型参数。这就是为什么您的功能一旦与inline
一起使用就变成string->string->string
的原因。
但是如果你标记你的函数string
,F#就不必修复参数,因为它不必将函数编译成IL,所以你的参数保持不变:< / p>
inline
答案 1 :(得分:2)
如果我理解正确,请使用内联:
let inline add a b = a + b
add 2 3 |> printfn "%A"
add "Hello " "World!" |> printfn "%A"
打印:
5
"Hello World!"
答案 2 :(得分:2)
将其设为inline
let inline add a b = a + b
(*
val inline add :
a: ^a -> b: ^b -> ^c
when ( ^a or ^b) : (static member ( + ) : ^a * ^b -> ^c)
*)
add "Hello " "World!"
// val it : string = "Hello World!"
add 2 3
// val it : int = 5