2013-12-13 2 views
3

У меня есть следующий код, который вернет seq из DownloadLink для этих адресов, которые могут быть проанализированы.Фильтровать и преобразовать `list option` в` list`?

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 
     ) 

Однако, я получил следующее сообщение об ошибке в printfn. Каков правильный способ его реализации? Должен ли я сделать это list option первым, а затем отфильтровать эти None элементов?

 
Error 1 Type mismatch. Expecting a 
    string -> DownloadLink  
but given a 
    string -> unit  
The type 'DownloadLink' does not match the type 'unit' 

ответ

4

Основная проблема заключается в том, что если у вас есть что-то вроде

match x with 
|true -> A 
|false -> B 

тип A и B должны быть одинаковыми.

Существует на самом деле построить в функции, которая сочетает в себе карту и фильтр, используя Some, что вы имели хотя - использовать Seq.choose как так

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 
     ) 
+0

Спасибо. 'Seq.choose' здесь так полезен. В противном случае я решил сначала создать опцию «seq», отфильтровать элементы «Нет», а затем переназначить обратно в 'seq ' из 'seq <опции DownloadLink>'. – ca9163d9

4

Помимо Seq.choose, вы можете также хорошо решить эту проблему с помощью выражений последовательности - где вы можете использовать yield возвращать результат в одной отрасли, но не для получения значения в другой ветви:

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 } 

в стороне, я бы не рекомендовал делать побочный эффект (печать) как часть вашего кода обработки. Если вы хотите сообщить об ошибках, возможно, лучше вернуть опцию (или определить тип, который либо Success, либо Error of string), так что отчет об ошибках отделен от обработки.

+0

Спасибо. Рад узнать, есть ли альтернативный способ сделать это. В конце концов я хочу регистрировать ошибки (в таблице базы данных или текстовом файле, возможно, и в преемнике). Каков наилучший способ реализовать ведение журнала (это также побочный эффект) в F #? – ca9163d9

+0

Я думаю, что запись внутри выражения последовательности прекрасна - печать является видимым пользователем побочным эффектом, поэтому имеет смысл справиться с ней хорошо, но ведение журнала - это нечто большее для внутренних целей, поэтому я не думаю, что есть проблема, когда его сделано как часть других вычислений (это своего рода точка ведения журнала :-)) –

+0

Я планирую использовать асинхронный журнал из этого проекта github. https://gist.github.com/ppanyukov/2026328 Хорошо ли обрабатывать как печать, так и ведение журнала? – ca9163d9

Смежные вопросы