tags:

views:

166

answers:

1

I'm wondering what others have come up with for dealing with Nullable<'T> in F#. I want to use Nullable<'T> on data types so that serialization works properly (i.e., doesn't write out F# option type to XML). But, I don't want my code stuck dealing with the ugliness of dealing with Nullable<'T> directly. Any suggestions?

Is it better to use active patterns to match directly on Nullable, or just a converter to option and use Some/None matching?

Additionally, I'd love to hear ideas on dealing with nullable references in a nice manner too. If I use, say "string option", then I end up with the F# option type wrapping things. If I don't then I can't distinguish between truly optional strings and strings that shouldn't be null.

Any chance .NET 4 will take on an Option<'T> to help out? (If it's part of the BCL, then we might see better support for it...)

+2  A: 

As active patterns as options plays nicely with pattern matching, but is seems by using active patterns (i.e. typeof and ??) your code will eat more ticks. The base question is how you will deal with your nullable references? In case your code is long chained computations it's nice to use monadic syntax:

type Maybe<'a> = (unit -> 'a option)

let succeed x : Maybe<'a> = fun () -> Some(x)
let fail : Maybe<'a> = fun () -> None
let run (a: Maybe<'a>) = a()
let bind p rest = match run p with None -> fail | Some r -> (rest r)
let delay f = fun () -> run (f ())

type MaybeBuilder() =
  member this.Return(x) = succeed x
  member this.Let(p,rest) = rest p
  member this.Bind(p,rest) = bind p rest
  member this.Delay(f) = delay f

let maybe = new MaybeBuilder()

let add (a:'a) (b:'a) =
  maybe {
    match TryGetNumericAssociation<'a>() with
    | Some v -> return (v.Add(a,b))
    | _ -> return! fail
  }

let add3 (a:'a) (b:'a) (c:'a) =
  maybe {
    let! ab = add a b
    let! abc = add ab c
    return abc
  }

> let r1 = add 1 2;;
val r1 : (unit -> int option)
> r1();;
val it : int option = Some 3
> let r2 = add "1" "2";;
val r2 : (unit -> string option)
> r2();;
val it : string option = None
> let r3 = add3 "one" "two" "three";;
val r3 : (unit -> string option)
> r3();;
val it : string option = None
ssp
Why don't you define the computation expression directly for type `'a option` but for `unit -> `a option`?
Dario
@Dario, I don't remember exactly, but it seems i wrote that code earlier while attempted to write adder for some types and i wanted to split effects in time. Of course, both versions can be written.
ssp