在F#中对序列进行类型测试,一般相等性测试

时间:2010-07-08 08:15:43

标签: .net f# equality

我试图测试两个元素的相等性。为什么我会在第一个模式匹配中得到错误:“没有任何正确的子类型,不能用作类型测试或运行时强制的来源”:

    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

谢谢!

3 个答案:

答案 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类已被密封)。