Тип теста в F # на последовательности, общий тест на равенство - PullRequest
4 голосов
/ 08 июля 2010

Я пытаюсь проверить равенство двух элементов. Почему я получаю сообщение об ошибке: «не имеет надлежащих подтипов и не может использоваться в качестве источника проверки типа или приведения во время выполнения», в первом сопоставлении с образцом:

    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 голосов
/ 08 июля 2010

Я не уверен, зачем вам это нужно - может быть проще хранить две последовательности в типе коллекции, который автоматически реализует структурное сравнение (поэлементное сравнение), такое как обычный список F #.

Однако вы можете написать это, используя нетипизированный IEnumerable, что позволит вам избежать необходимости указывать параметр общего типа для seq<_> в сопоставлении с образцом (что не всегда возможно).Вам нужен простой помощник для преобразования неуниверсального IEnumerable в seq<obj>:

open System.Collections

let ofUntyped (a:IEnumerable) =
  seq { let en = a.GetEnumerator() 
        while en.MoveNext() do
          yield en.Current }

[ EDIT : Вы можете использовать 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 
0 голосов
/ 08 июля 2010

Почему я получаю ошибку: "не имеет любые правильные подтипы и не могут быть использованы в качестве источника типового теста или принуждение во время выполнения ", в первом образец соответствия

Поскольку тип System.Tuple<System.Collections.Generic.IEnumerable<System.Object>,System.Collections.Generic.IEnumerable<System.Object>>, a.k.a. (seq<obj>*seq<obj>) не имеет никаких подтипов (класс Tuple закрыт).

0 голосов
/ 08 июля 2010

Предупреждение: это довольно некрасиво. Мне очень любопытно более элегантные подходы.

Нет (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 <_> до 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

Это сказал, я думаю, что это довольно уродливый хак. Я бы предложил написать функцию сравнения последовательностей, которая проверяет только последовательности.

...