gpt4 book ai didi

F# 比较与 C# IComparable

转载 作者:行者123 更新时间:2023-12-04 11:39:28 24 4
gpt4 key购买 nike

简而言之,我的问题是:

在需要 IComparable 的 C# 容器中存储元组(或任何具有“比较”约束的类型)时,我能做些什么?

这有效:

> let x (y : 'a when 'a : comparison) = y ;;
val x : y:'a -> 'a when 'a : comparison

> x (1,2) ;;
val it : int * int = (1, 2)

我原以为这会起作用:
> let x (y : IComparable<int>) = y ;;

val x : y:IComparable<int> -> IComparable<int>

> x (1,2) ;;

x (1,2) ;;
---^^^

stdin(28,4): error FS0001: The type ''a * 'b' is not compatible with the type 'IComparable<int>'

这也是:
> let x (y : IComparable) = y ;;

val x : y:IComparable -> IComparable

> x (1,2) ;;

x (1,2) ;;
---^^^

stdin(30,4): error FS0001: The type ''a * 'b' is not compatible with the type 'IComparable'

编辑

我遵循 F# 不进行隐式向上转换的论点。但是,即使是明确的:
> (1, 2) :> IComparable ;;

(1, 2) :> IComparable ;;
^^^^^^^^^^^^^^^^^^^^^

stdin(43,1): error FS0193: Type constraint mismatch. The type
int * int
is not compatible with type
IComparable
The type 'int * int' is not compatible with the type 'IComparable'

我认为这是有道理的,因为 F# 元组的可比性是在 F# 类型系统中从结构上推断出来的,并且也许 .NET 无法获得额外的信息。

似乎以下评论的一种解决方法正在调用
Tuple<_,_> (1,2) ;;

甚至
box (1, 2) :?> IComparable ;;

最佳答案

F# 不像 C# 那样进行隐式向上转换。如果您请求 IComparable ,那么您正在请求 IComparable不是 可以上载到 IComparable 的东西
你真正想要的是请求一个恰好实现 IComparable 的类型,但您仍在使用特定类型。
这就是为什么let x (y : 'a when 'a : comparison) , 见 y'a 类型, 而 'a可以静态向上转换为 comparison (如果你想访问 comparison 的成员,你必须先使用 comparison 向上转换到 :>)
另一方面let x (y : IComparable<int>) = y非常明确地请求 IComparable<int> .但是你正在通过(1,2) ,一个值,可以向上转换为 IComparable .所以如果你通过 (1,2) :> IComparable<int>甚至(1,2) :> _ ,编译器将能够传递该值。你可以总结比较,但是 如果丢失类型信息,返回值将是 IComparable不再是 int*int .

let wrapComparable value = 
{
new IComparable with
member this.CompareTo other =
match other with
| :? 'a as other -> compare value other
| _ -> raise <| InvalidOperationException()
}
另外,在这里您需要考虑, IComparable基于 obj所以你可能需要考虑这种情况,你的 other是不同的类型。
以防万一,您只需要 IComparable<'a>代码变得更简单:
let wrapComparable value = 
{
new IComparable<_> with
member this.CompareTo other = compare value other
}
因此,根据经验,您通常希望创建具有类型约束的泛型函数,而不是像在 C# 中那样请求接口(interface)。这是因为 F# 不进行自动向上转换。
关于相等和比较的非常详细的解释可以在 http://lorgonblog.wordpress.com/2009/11/08/motivating-f-equality-and-comparison-constraints/ 中找到。和 http://blogs.msdn.com/b/dsyme/archive/2009/11/08/equality-and-comparison-constraints-in-f-1-9-7.aspx . MSDN 还指出,

If you are only using tuples from F# and not exposing them to other languages, and if you are not targeting a version of the .NET Framework that preceded version 4, you can ignore this section.

Tuples are compiled into objects of one of several generic types, all named Tuple, that are overloaded on the arity, or number of type parameters. Tuple types appear in this form when you view them from another language, such as C# or Visual Basic, or when you are using a tool that is not aware of F# constructs. The Tuple types were introduced in .NET Framework 4. If you are targeting an earlier version of the .NET Framework, the compiler uses versions of System.Tuple from the 2.0 version of the F# Core Library. The types in this library are used only for applications that target the 2.0, 3.0, and 3.5 versions of the .NET Framework. Type forwarding is used to ensure binary compatibility between .NET Framework 2.0 and .NET Framework 4 F# components.


所以看起来,Tuples 恰好是 System.Tuple 的事实实际上只是一个实现细节,此时缺少 IComparison有点道理。

关于F# 比较与 C# IComparable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18091887/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com