10

私は F# を学んでいて、シーケンスとmatch式の両方をいじり始めました。

私は、次のような HTML を調べて<span>pagingクラスを持つ親の最後の URL を取得する Web スクレイパーを作成しています。

<html>
<body>
    <span class="paging">
        <a href="http://google.com">Link to Google</a>
        <a href="http://TheLinkIWant.com">The Link I want</a>
    </span>
</body>
</html>

最後の URL を取得しようとする試みは次のとおりです。

type AnHtmlPage = FSharp.Data.HtmlProvider<"http://somesite.com">

let findMaxPageNumber (page:AnHtmlPage)= 
    page.Html.Descendants()
    |> Seq.filter(fun n -> n.HasClass("paging"))
    |> Seq.collect(fun n -> n.Descendants() |> Seq.filter(fun m -> m.HasName("a")))
    |> Seq.last
    |> fun n -> n.AttributeValue("href")

ただし、検索しているクラスがページにない場合、問題が発生します。特に、次のメッセージで ArgumentExceptions を取得します。Additional information: The input sequence was empty.

paging私が最初に考えたのは、空のシーケンスに一致し、クラスがページに見つからなかったときに空の文字列を返す別の関数を作成することでした。

let findUrlOrReturnEmptyString (span:seq<HtmlNode>) =
    match span with 
    | Seq.empty -> String.Empty      // <----- This is invalid
    | span -> span
    |> Seq.collect(fun (n:HtmlNode) -> n.Descendants() |> Seq.filter(fun m -> m.HasName("a")))
    |> Seq.last
    |> fun n -> n.AttributeValue("href")

let findMaxPageNumber (page:AnHtmlPage)= 
    page.Html.Descendants()
    |> Seq.filter(fun n -> n.HasClass("paging"))
    |> findUrlOrReturnEmptyStrin

私の問題はSeq.Empty、リテラルではなく、パターンで使用できないことです。パターン マッチングを使用するほとんどの例では[]、パターンに空のリストが指定されているため、疑問に思っています: 同様のアプローチを使用して空のシーケンスに一致させるにはどうすればよいでしょうか?

4

4 に答える 4

15

ildjarn がコメントで与えた提案は良いものです: を使用matchするとより読みやすいコードが作成されると思われる場合は、空の seq をチェックするアクティブなパターンを作成します。

let (|EmptySeq|_|) a = if Seq.isEmpty a then Some () else None

let s0 = Seq.empty<int>

match s0 with
| EmptySeq -> "empty"
| _ -> "not empty"

これを F# インタラクティブで実行すると、結果は になります"empty"

于 2016-08-12T03:15:23.493 に答える
13

whenガードを使用して、ケースをさらに限定することができます。

match span with 
| sequence when Seq.isEmpty sequence -> String.Empty
| span -> span
|> Seq.collect (fun (n: HtmlNode) ->
    n.Descendants()
    |> Seq.filter (fun m -> m.HasName("a")))
|> Seq.last
|> fun n -> n.AttributeValue("href")

この場合、ildjarn は正しいですif...then...elseが、より読みやすい代替手段である可能性があります。

于 2016-08-11T22:48:33.537 に答える
2

@rmunn からの回答に基づいて、より一般的なシーケンス等価アクティブ パターンを作成できます。

let (|Seq|_|) test input =
    if Seq.compareWith Operators.compare input test = 0
        then Some ()
        else None

match [] with
| Seq [] -> "empty"
| _ -> "not empty"
于 2016-08-12T07:27:50.160 に答える