1

I have the following f# code

product.code <- productPage.Html
    .Descendants["li"]
    .Select(fun node -> node.InnerText())
    .Where(fun link -> (Regex.Match(link,@"code:").Success))
    .FirstOrDefault()
    .Replace("code:", "")
    .Trim()

I'm having some trouble with nulls. In c# I would do something like this.

product.code = productPage?.Html
    ?.Descendants["li"]
    ?.Select(node => node.InnerText())
    ?.Where(link => Regex.Match(link,@"code:").Success)
    ?.FirstOrDefault()
    ?.Replace("code:", "")
    ?.Trim() ?? "Not Found"

Is this possible?

Spaceman
  • 1,319
  • 13
  • 42
  • 2
    In F# `productPage` itself should be an `Option` or whatever the type is, not a `null`. Option [has members](https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/options#option-module) Option.map, option.iter. Which library are you using? Does it return nulls or options? Perhaps there's an F# wrapper or altenrative for it? – Panagiotis Kanavos Feb 12 '19 at 12:30
  • 1
    Possible duplicate of [Is there conditional access operator in F# (similar to new ?. in C#)?](https://stackoverflow.com/questions/24077105/is-there-conditional-access-operator-in-f-similar-to-new-in-c) – abcalphabet Feb 12 '19 at 12:30
  • Something like the [HtmlParser](http://fsharp.github.io/FSharp.Data/library/HtmlParser.html) from the F# Data package? – Panagiotis Kanavos Feb 12 '19 at 12:31
  • 3
    Possible duplicate of [Null Coalescing Operator in F#?](https://stackoverflow.com/questions/21194565/null-coalescing-operator-in-f) – Mark Shevchenko Feb 12 '19 at 12:31
  • This is a dup sorry folks ill close it – Spaceman Feb 12 '19 at 12:31
  • 1
    @Spaceman maybe, maybe not. DId you check HtmlParser? The answer is to *avoid nulls in the first place*. Which library are you using? You could use eg `productPage.Html |> Option.map page->...` instead of checking for nulls – Panagiotis Kanavos Feb 12 '19 at 12:32

1 Answers1

3

In the second example, it looks to me like "?." has to be carried through the whole call chain due to its initial use. Rather than try to recreate this operator and preserve how this looks in C#, I suggest you go for more idiomatic F#. For example:

module String =
    let replace (oldValue: string) (newValue: string) (s: string) =
        s.Replace (oldValue, newValue)

    let trim (s: string) =
        s.Trim()

let result =
    match isNull productPage with
    | true -> None
    | false ->
        productPage.Html.Descendants.["li"]
        |> Seq.map (fun node -> node.InnerText())
        |> Seq.tryPick (fun link -> (Regex.Match (link, "code:").Success))

let code =
    match result with
    | Some html -> 
        html
        |> String.replace "code:" ""
        |> String.trim
    | None -> "Not Found" 

product.code <- code
Jim Foye
  • 1,918
  • 1
  • 13
  • 15