键入不匹配错误.F#类型推断失败?

Nat*_*anD 2 .net f# functional-programming type-inference f#-interactive

我正在尝试在F#中编写一个方法,该方法根据传递给方法的值的类型返回泛型类型的新实例.在FSI:

 open System.Collections.Generic

 type AttributeIndex<'a>() = 
    inherit SortedDictionary<'a, HashSet<int array>>()

 let getNewIndexForValue (value: obj) : AttributeIndex<_> =
    match value with
      | :? string -> new AttributeIndex<string>()
      | :? int -> new AttributeIndex<int>()
      | :? float -> new AttributeIndex<float>()
      | :? bool -> new AttributeIndex<bool>()
      | _ -> failwith "bad value type"

 let someIndexes = [
    getNewIndexForValue 9;
    getNewIndexForValue "testString";
    getNewIndexForValue false;
    getNewIndexForValue 5.67;
 ]

 someIndexes;;
Run Code Online (Sandbox Code Playgroud)

这不会编译错误

error FS0001: Type mismatch. Expecting a AttributeIndex<string>
but given a AttributeIndex<int>
The type 'string' does not match the type 'int'

我似乎无法弄清楚如何根据传递给函数的value参数的类型,使用类型param获取Attribute的实例.我尝试过其他几种变体,但都会导致相同的类型不匹配错误.任何帮助将不胜感激.谢谢!!

更新:

谢谢你的回答.我现在明白了.所以现在我试图让'getNewIndexForValue'返回一个非泛型的基本AttributeIndex类.我在C#中实现了它,它按照我的预期进行编译和运行:

using System;
using System.Collections.Generic;

namespace Example {

    public class AttributeIndexBase : SortedDictionary<object, HashSet<int[]>> { }

    public class AttributeIndex<T> : AttributeIndexBase {
        public void AddToIndex(T indexValue, int[] recordKey) {
            if (!this.ContainsKey(indexValue)) {
                this.Add(indexValue, new HashSet<int[]> { recordKey });
            }
            else {
                this[indexValue].Add(recordKey);
            }
        }
    }

    class Program {
        static int Main(string[] args) {
            var intIdx = GetIndexForValue(32);
            var boolIdx = GetIndexForValue(true);
            var doubleIdx = GetIndexForValue(45.67);
            var someIndexes = new List<AttributeIndexBase> {
                intIdx,
                boolIdx,
                doubleIdx
            };
            return 0;
        }

        static AttributeIndexBase GetIndexForValue(object value) {
            switch (value.GetType().Name.ToLower()) {
                case "int32" :
                    return new AttributeIndex<int>();
                case "single" :
                    return new AttributeIndex<float>();
                case "double" :
                    return new AttributeIndex<double>();
                case "boolean" :
                    return new AttributeIndex<bool>();
                default :
                    throw new ArgumentException("The type of the value param is not allowed", "value");
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,尝试将此端口移植到F#不起作用:

  module example

     open System
     open System.Collections.Generic

     type AttributeIndexBase() = 
        inherit SortedDictionary<obj, HashSet<int array>>()

     type AttributeIndex<'a>() = 
        inherit AttributeIndexBase()

     let getNewIndexForValueType (value: ValueType) : AttributeIndexBase =
        match value with
           | :? int -> new AttributeIndex<int>()
           | :? float -> new AttributeIndex<float>()
           | :? bool -> new AttributeIndex<bool>()
           | _ -> failwith "bad value type"

     let someIndexes = [
        getNewIndexForValueType 9;
        getNewIndexForValueType false;
        getNewIndexForValueType 5.67;
     ]
Run Code Online (Sandbox Code Playgroud)

在我看来,这是一个非常直接的端口(除了在F#版本中我将它限制为ValueType),但是我得到错误:

error FS0001: This expression was expected to have type AttributeIndexBase
but here has type AttributeIndex<int>

F#真的不支持像C#这样的子类转换为父类吗?

kvb*_*kvb 6

您的最新代码几乎可以正常工作,但AttributeIndexBase在这种情况下,F#要求您明确地向上转换.至少有两种方法可以执行此操作:您可以使用upcast关键字,也可以使用:>转换运算符.

第一个选项看起来像这样:

let getNewIndexForValueType (value: ValueType) : AttributeIndexBase =
  match value with
     | :? int -> upcast new AttributeIndex<int>()
     | :? float -> upcast new AttributeIndex<float>()
     | :? bool -> upcast AttributeIndex<bool>()
     | _ -> failwith "bad value type"
Run Code Online (Sandbox Code Playgroud)

而第二个看起来像这样:

let getNewIndexForValueType (value: ValueType) : AttributeIndexBase =
  match value with
     | :? int -> new AttributeIndex<int>() :> _
     | :? float -> new AttributeIndex<float>() :> _
     | :? bool -> new AttributeIndex<bool>() :> _
     | _ -> failwith "bad value type"
Run Code Online (Sandbox Code Playgroud)