Reputation: 29159
I have the following code which will return a seq
of DownloadLink
for these Urls that can be parsed.
type DownloadLink = { Url: string; Period: DateTime }
nodes |> Seq.map (fun n ->
let url = n.Attributes.["href"].Value
match url with
| Helper.ParseRegex "[a-zA-Z](?<period>\d{4})\.txt" [period] ->
{ Url = url; Period = period }
| _ ->
printfn "Cannot parse %s" url // Error
)
However, I got the following error at the printfn
. What's right way to implement it? Should I make it a list option
first and then filter out these None
items?
Error 1 Type mismatch. Expecting a string -> DownloadLink but given a string -> unit The type 'DownloadLink' does not match the type 'unit'
Upvotes: 3
Views: 1107
Reputation: 243041
Aside from Seq.choose
, you can also nicely solve the problem using sequence expressions - where you can use yield
to return result in one branch, but do not have to produce a value in another branch:
seq { for n in nodes do
let url = n.Attributes.["href"].Value
match url with
| Helper.ParseRegex "[a-zA-Z](?<period>\d{4})\.txt" [period] ->
yield { Url = url; Period = period }
| _ ->
printfn "Cannot parse %s" url }
Aside, I would not recommend doing a side effect (printing) as part of your processing code. If you want to report errors, it might be better to return an option (or define a type which is either Success
or Error of string
) so that the error reporting is separated from processing.
Upvotes: 5
Reputation: 25516
The basic problem is that if you have something like
match x with
|true -> A
|false -> B
the type of A
and B
must be the same.
There is actually a build in function that combines the map and filter using Some
that you had though of - use Seq.choose
like so
nodes |> Seq.choose (fun n ->
let url = n.Attributes.["href"].Value
match url with
| Helper.ParseRegex "[a-zA-Z](?<period>\d{4})\.txt" [period] ->
Some ({ Url = url; Period = period })
| _ ->
printfn "Cannot parse %s" url // Error
None
)
Upvotes: 6