Generics FSharp:具有泛型的类型推断

Generics FSharp:具有泛型的类型推断,generics,f#,type-inference,Generics,F#,Type Inference,我不明白为什么下面的代码不能编译 module GenericsTest = open System type Dog = { name:string } type Apple = { size:int } let get<'a> (id:string) = Activator.CreateInstance<'a>() let creatorInferred

我不明白为什么下面的代码不能编译

module GenericsTest = 
    open System

    type Dog = {
        name:string
    }

    type Apple = {
        size:int
    }

    let get<'a> (id:string) =
        Activator.CreateInstance<'a>()

    let creatorInferred getAsParam = 
        let apple = {
            name = getAsParam "some-apple"
        }

        let dog = {
            size = getAsParam "some-dog"
        }
        (apple, dog)

    let creatorWithTypeAnnotation (getAsParam:string->'a) = 
        let apple = {
            name = getAsParam "some-apple"
        }

        let dog = {
            size = getAsParam "some-dog"
        }
        (apple, dog)
模块GenericsTest=
开放系统
类型狗={
名称:string
}
苹果类型={
大小:int
}
让我们开始
让creatorInferred getAsParam=
让苹果={
name=getAsParam“一些苹果”
}
让狗{
大小=getAsParam“一些狗”
}
(苹果,狗)
让creatorWithTypeAnnotation(getAsParam:string->'a)=
让苹果={
name=getAsParam“一些苹果”
}
让狗{
大小=getAsParam“一些狗”
}
(苹果,狗)
如果查看2“creator…”函数,它们都会给出编译错误

此表达式的类型应为int。。。但是这里有 类型字符串

我可以看到,F#推断getAsParam方法的返回类型为int,因为它是它遇到的第一个返回类型。但是,为什么不决定使用泛型返回类型呢

正如您所看到的,我已经尝试在creatorWithTypeAnnotation方法中为函数签名创建一个函数,但这没有任何影响

我被难住了!我如何强迫它认识到getAsParam函数应该返回一个泛型?

下面是一个快速的F#交互式会话,通过使用一个接口(它必须是某种
成员,当然也可以是类上的一个方法):

>键入ipram=abstract getParam:string->'a;;
IPRAM型=
接口
抽象成员getParam:string->'a
结束
>让createWith(p:ipram):int*bool=(p.getParam“a”,p.getParam“b”);;
val createWith:p:IParam->int*bool
>让test={new IParam with member _u.getParam s=Unchecked.defaultof};;
val测试:IParam
>进行测试;;
val it:int*bool=(0,false)
不过,您可能会发现实现一些更健全的
ipram实例并不容易

这里是一个快速的F#交互式会话,我指的是通过使用接口作弊(它必须是某种
成员
,因此它当然也可以是类中的一种方法):

>键入ipram=abstract getParam:string->'a;;
IPRAM型=
接口
抽象成员getParam:string->'a
结束
>让createWith(p:ipram):int*bool=(p.getParam“a”,p.getParam“b”);;
val createWith:p:IParam->int*bool
>让test={new IParam with member _u.getParam s=Unchecked.defaultof};;
val测试:IParam
>进行测试;;
val it:int*bool=(0,false)
不过,您可能会发现实现一些更健全的
ipram实例并不容易

这里是一个快速的F#交互式会话,我指的是通过使用接口作弊(它必须是某种
成员
,因此它当然也可以是类中的一种方法):

>键入ipram=abstract getParam:string->'a;;
IPRAM型=
接口
抽象成员getParam:string->'a
结束
>让createWith(p:ipram):int*bool=(p.getParam“a”,p.getParam“b”);;
val createWith:p:IParam->int*bool
>让test={new IParam with member _u.getParam s=Unchecked.defaultof};;
val测试:IParam
>进行测试;;
val it:int*bool=(0,false)
不过,您可能会发现实现一些更健全的
ipram实例并不容易

这里是一个快速的F#交互式会话,我指的是通过使用接口作弊(它必须是某种
成员
,因此它当然也可以是类中的一种方法):

>键入ipram=abstract getParam:string->'a;;
IPRAM型=
接口
抽象成员getParam:string->'a
结束
>让createWith(p:ipram):int*bool=(p.getParam“a”,p.getParam“b”);;
val createWith:p:IParam->int*bool
>让test={new IParam with member _u.getParam s=Unchecked.defaultof};;
val测试:IParam
>进行测试;;
val it:int*bool=(0,false)

不过,您可能会发现实现一些更健全的
ipram实例并不容易

正如Carsten所暗示的,类型变量都是在编译时解析的。如果将
getAsParam
定义为
string->'a
,则不会阻止编译时解析
'a
。因为它不能在编译时解析为两种不同的类型,所以编译失败

以你的例子为例:

let creatorWithTypeAnnotation (getAsParam:string->'a) = 
    let apple = {
        name = getAsParam "some-apple"
    }

    let dog = {
        size = getAsParam "some-dog"
    }
这也可以这样声明(我将使用
'A
而不是
'A
,因为预期的约定是小写类型变量用于编译器推断的类型):


让creatorWithTypeAnnotation正如Carsten所暗示的,类型变量都在编译时解析。如果将
getAsParam
定义为
string->'a
,则不会阻止编译时解析
'a
。因为它不能在编译时解析为两种不同的类型,所以编译失败

以你的例子为例:

let creatorWithTypeAnnotation (getAsParam:string->'a) = 
    let apple = {
        name = getAsParam "some-apple"
    }

    let dog = {
        size = getAsParam "some-dog"
    }
这也可以这样声明(我将使用
'A
而不是
'A
,因为预期的约定是小写类型变量用于编译器推断的类型):


让creatorWithTypeAnnotation正如Carsten所暗示的,类型变量都在编译时解析。如果将
getAsParam
定义为
string->'a
,则不会阻止编译时解析
'a
。因为它不能在编译时解析为两个不同的t
let creatorWithTypeAnnotation<'A> (getAsParam:string->'A) = 
    let apple = {
        name = getAsParam "some-apple"
    }

    let dog = {
        size = getAsParam "some-dog"
    }