我试图测试两个元素的相等性。为什么我会在第一个模式匹配中得到错误:“没有任何正确的子类型,不能用作类型测试或运行时强制的来源”:
let eq a b =
match (a,b) with
| :? (seq<_>*seq<_>) -> Seq.map2( fun xA xB -> xA=xB ) a b
|> Seq.fold( fun res elem -> res && elem ) true
| :? _ -> a=b
谢谢!
答案 0 :(得分:0)
警告:这很难看。我对更优雅的方法很好奇。
没有(seq * seq)类型。您必须单独测试每个参数。像
这样的东西match (a,b) with
| (:? seq<_> as seqa), (:? seq<_> as seqb) -> ...
但这会产生编译错误,因为a和b的类型需要更多的类型注释。但这会限制参数,使你无法做到像eq 2 2那样的事情。
下面的代码段可以解决这个问题:
let eq a b =
match (box a, box b) with
| (:? seq<_> as seqa), (:? seq<_> as seqb) ->
printfn "comparing sequences..."
Seq.map2 (fun xA xB -> xA = xB) seqa seqb |> Seq.forall id
| _ -> printfn "comparing default..."
a=b
但比较两个序列的结果并不是预期的结果:
> eq {1..10} {1..10};;
comparing default...
val it : bool = false
它跳转到第二个匹配子句。这是因为编译器限制了类型seq&lt; _&gt;到seq,它喂了两个seq。
为了比较两个序列,需要将它们转换为Seq,如下所示:
> eq1 (Seq.map box {1..10}) (Seq.map box {1..10});;
comparing sequences...
val it : bool = true
> eq1 (Seq.map box {1..10}) (Seq.map box {1L..10L});;
comparing sequences...
val it : bool = false
这说,我认为这是一个相当丑陋的黑客。我建议编写一个只测试序列的序列比较函数。
答案 1 :(得分:0)
我不确定你为什么需要这个 - 将两个序列存储在一个自动实现结构比较(元素比较)的集合类型中可能更容易,例如普通的F#list。
但是,您可以使用无类型IEnumerable
来编写此内容,这样可以避免在模式匹配中为seq<_>
指定泛型类型参数(这是不可能的)。您需要一个简单的帮助器才能将非通用IEnumerable
转换为seq<obj>
:
open System.Collections
let ofUntyped (a:IEnumerable) =
seq { let en = a.GetEnumerator()
while en.MoveNext() do
yield en.Current }
[编辑:您可以使用Seq.cast<obj>
代替我写的帮助程序]
其余代码与原始版本几乎相同。您只需在模式匹配中查找IEnumerable
,然后使用ofUntyped
转换序列:
let eq (a:obj) (b:obj) =
match a, b with
| (:? IEnumerable as ae), (:? IEnumerable as be) ->
Seq.map2( fun xA xB -> xA = xB) (ofUntyped ae) (ofUntyped be)
|> Seq.fold( fun res elem -> res && elem ) true
| _ -> a = b
答案 2 :(得分:0)
为什么我会收到错误:“没有 任何适当的亚型,不能使用 作为类型测试的来源或 运行时强制“,在第一个 模式匹配
因为类型System.Tuple<System.Collections.Generic.IEnumerable<System.Object>,System.Collections.Generic.IEnumerable<System.Object>>
,a.k.a。(seq<obj>*seq<obj>)
没有任何子类型(Tuple
类已被密封)。