Search code examples
f#seq

Using Pipe Forward with nested sequences


I'm brand new to F# so I apologize if I'm using the incorrect names for things.

I'm trying to use F# to parse a web page that looks something like this:

<!--This is simplified, in reality there are more divs, anchors etc. -->
<html>
<body> 
    <div class="pr-single"><a href="http://google.ca">Google</a></div>
    <div class="pr-single"><a href="http://apple.com">Apple</a></div>
    <div class="pr-single"><a href="http://microsoft.com">Microsoft</a></div>
</body>
</html>

I've declared a type

type PromoterPage = FSharp.Data.HtmlProvider<"http://somewebpage.com">

And now I'm trying to get a list of all the links on the page. My thought process was to:

  1. Get all the outer divs by class name
  2. Get the descendants of all of these divs
  3. Collect these descendants into a flat list
  4. Filter this list down to only <a> tags

My attempt at this is below:

let GetFirst (page:PromoterPage) = 
    page.Html.Descendants()
    |> Seq.filter(fun n -> n.HasClass("pr-single"))                 //Find the divs
    |> Seq.map(fun n -> n.Descendants())                            //Get the descendants
    |> Seq.collect(fun n -> n |> Seq.where(fun m -> m.HasName("a")) //Filter and collect the anchors

The problem seems to be that you can't nest Seq functions or that I'm doing it improperly. I receive the error:

Incomplete values or function definition. If this is an expression, the body of the expression must be indented to the same column as the keyword.

Can I nest Seq functions the way I'm trying to here? Am I thinking about this in the wrong way?


Solution

  • You're missing the closing parentheses:

    |> Seq.collect(fun n -> n |> Seq.where(fun m -> m.HasName("a")))
    

    Can I nest Seq functions the way I'm trying to here?

    Yes, it is perfectly fine to nest functions with piping in lambdas. However, I often pull them out into local functions, as it can make the code more readable in the long run.