.net - 类型不匹配错误。 F# 类型推断失败?

标签 .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;;

编译不会出错

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

我似乎无法弄清楚如何根据传递给函数的值参数的类型来获取具有类型参数的 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");
            }
        }
    }
}

但是,尝试将其移植到 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;
     ]

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

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

F# 真的不像 C# 那样支持从子类型到父类型的转换吗?

最佳答案

您的最新代码几乎可以工作,但 F# 要求您在这种情况下显式向上转换为 AttributeIndexBase。至少有两种方法可以做到这一点:您可以使用 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"

虽然第二个看起来像这样:

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

关于.net - 类型不匹配错误。 F# 类型推断失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3532637/

相关文章:

c# - 将 C# 对象方法链接转换为 F#

f# - 计算表达式中的归零和合并

functional-programming - 函数式编程:不变的数据结构效率

haskell - 没有反引号的函数 elem 不起作用

c# - 在c#中初始化多维对象数组

c# - 为什么 DefaultIfEmpty 是这样实现的?

.net - AppDynamics 或 NewRelic 类型的系统 - 它是如何工作的?

F# 类型提供程序,它们如何工作

c# - 如何使 Form 和 HWND 相互重新定位?

generics - F# 使用类型变量调用内联函数