.net 类型不匹配错误。F#类型推断失败?
我试图在F#中编写一个方法,该方法根据传入该方法的值的类型返回泛型类型的新实例。在FSI中:.net 类型不匹配错误。F#类型推断失败?,.net,f#,functional-programming,type-inference,f#-interactive,.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<_> =
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;;
open System.Collections.Generic
类型AttributeIndex()
让getNewIndexForValue(值:obj):AttributeIndex=
匹配值
| :? 字符串->新属性索引()
| :? int->新属性索引()
| :? 浮动->新属性索引()
| :? bool->新属性索引()
|_u824;->故障类型为“错误值类型”
让一些索引=[
getNewIndexForValue 9;
getNewIndexForValue“testString”;
getNewIndexForValue为false;
getNewIndexForValue 5.67;
]
一些指数;;
这不会编译时出错
错误FS0001:类型不匹配。期待
属性索引
但是给一个
属性索引
类型“string”与类型“int”不匹配。
我似乎不知道如何根据传递到函数中的value参数的类型获取类型为param的属性实例。我尝试了其他几种变体,但都会导致相同的类型不匹配错误。任何帮助都将不胜感激。谢谢
更新:
谢谢你的回答。我现在明白了。所以现在我尝试让我的“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");
}
}
}
}
使用系统;
使用System.Collections.Generic;
名称空间示例{
公共类AttributeIndexBase:SortedDictionary{}
公共类AttributeIndex:AttributeIndexBase{
public void AddToIndex(T indexValue,int[]记录键){
如果(!this.ContainsKey(indexValue)){
Add(indexValue,新HashSet{recordKey});
}
否则{
此[indexValue].Add(recordKey);
}
}
}
班级计划{
静态int Main(字符串[]args){
var intIdx=GetIndexForValue(32);
var boolIdx=GetIndexForValue(真);
var doubleIdx=GetIndexForValue(45.67);
var someindex=新列表{
intIdx,
布利克斯,
双IDX
};
返回0;
}
静态属性索引数据库GetIndexForValue(对象值){
开关(value.GetType().Name.ToLower()){
案例“int32”:
返回新的AttributeIndex();
“单一”情况:
返回新的AttributeIndex();
“双重”情况:
返回新的AttributeIndex();
案例“布尔”:
返回新的AttributeIndex();
违约:
抛出新ArgumentException(“不允许值参数的类型”,“值”);
}
}
}
}
但是,尝试将其移植到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;
]
模块示例
开放系统
open System.Collections.Generic
类型AttributeIndexBase()=
继承SortedDictionary()
键入AttributeIndex无法为函数返回值提供通用参数的事实是一个红色标志:
let getNewIndexForValue (value: obj) : AttributeIndex< ?? what goes here > =
让getNewIndexForValue(值:obj):AttributeIndex<??这里有什么>=
getNewIndexForValue
函数必须为'a
参数选择一种类型;'a
类型参数可以是string、int、float或bool,但不能同时为所有参数
一种可能是引入一个非泛型的AttributeIndex
类,该类的AttributeIndex问题是您试图获得一个非泛型方法来返回不同的绑定泛型类型。这是不可能的。这相当于在C#中尝试以下内容
让我们看看这一行:
let getNewIndexForValue (value: obj) : AttributeIndex<_> =
让getNewIndexForValue(值:obj):AttributeIndex=
AttributeIndex
中的下划线对编译器意味着:嘿,找出要插入的类型。它基本上只保存了一些击键。如果您返回一个属性索引
,编译器将分别推断
为字符串
,或bool
或int
您要做的是在这里返回不同的类型。这不是关于某种类型,而是关于允许的任何类型。这与Java的通用通配符基本不同
- Java的
列表
是任何可能值的列表(如对象
可以)
- F#的
列表
正好是一种类型的列表
您需要的是Java通配符,在.NET下,您可以通过co/contravariant类型在那里进行表示
因此,您需要AttributeIndex
我最初将此作为一条评论发布,但实际上这是“答案”:
你打算用它做什么
“someIndexes”之后
除非你具体说明,否则任何“答案”都只是空泛的猜测。我们无法提供有关如何克服此“类型错误”的规定性建议,因为根据您最终打算如何使用数据,有许多可能的克服方法。我认为@JaredPar的答案最有可能是你想要的,但这基本上是我试图成为通灵者(以及其他所有答案)
一旦您对每个索引指定了“您想做什么”,那么这就意味着所有索引都需要支持一个公共接口或基类,这就是您的答案。其他人都是对的,但我想我可以补充一点解释
F#中的每个表达式都有一个类型。在F#中,“if a then b else c”是一个表达式,返回b或c。要使其工作,b和c必须具有相同的类型。“match…”也是一个表达式,返回其中一个子句的值。这意味着每个子句必须具有相同的类型
您的匹配表达式试图违反此规则。每个子句都有不同的类型
type AttributeIndex =
member GetValue : object -> HashSet<int array>
type AttributeIndex<'a> =
inherit AttributeIndex
inherit IDictionary<'a, HashSet<int array>>
let getNewIndexForValue (value: obj) : AttributeIndex<_> =
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"