らくがき

2008/04/09

[F#] .NETライブラリから返される「null値」はどのように扱えばよい?

boxing 機能を用いることで、「null値」と比較できます。
box (value) <> null
パターンマッチで判断することもできます。
match x.ReadLine() with 
| null -> None 
| line -> Some(line)
.NETライブラリで最終的に null値 を返す関数を扱うときの多相的関数(ジェネリック関数)
#light

/// Usage: "SeqGivenFuncTillNull<string>(sr.ReadLine)"
let SeqGivenFuncTillNull<'a when 'a:not struct> (f:unit->'a) :seq<'a> =
  seq {
        let v = ref (f()) in
        while box (!v) <> null do
          yield !v
          do v := f()
      }
StringReader を例にすると、以下のようになります。
let str = "testeseテスト!\ndeoweiru!ewp!";;
let sr = new StringReader(str);;

let lineSeq = SeqGivenFuncTillNull<string>(sr.ReadLine);;

let main =
  for line in lineSeq do
    printfn "%s" line
  done
StringReader は TextReader を継承しているので、 TextReader を拡張し、"SeqGivenFuncTillNull"を意識しないようにもできます。
/// Extend IO.TextReader.
type System.IO.TextReader with
  member it.to_string_seq = SeqGivenFuncTillNull<string>(it.ReadLine)

// Usage:
let s = "first line\nsecond line\nthird line\n"
let sr2 = new System.IO.StringReader(s)
for line in sr2.to_string_seq do   // Life is good :)
  printfn "%s" line;;
また、F#で扱いやすいように Option で包むことも可能です。
type System.IO.TextReader with 
    member x.TryReadLine() = 
        match x.ReadLine() with 
        | null -> None 
        | line -> Some(line)

let SeqGivenFuncTillNull2 (f:unit->'a option) :seq<'a> =
  seq {
        let v = ref (f())
        while (!v) <> None do
          yield Option.get (!v)
          do v := f()
      }

Labels:

0 Comments:

Post a Comment

<< Home