1
votes

Say I have DUs

type Zero = Zero
type Succ<'a> = Succ of 'a

I can use Unchecked.defaultof<Zero Succ Succ> when I'm passing the value to an inline function that only uses the type of that value. But how would I go about getting a proper value of a given type? One that isn't null.

Since the only valid value that has a type Zero Succ Succ is Succ(Succ(Zero)) I feel like I should be able to get it.

I don't care for intermediate type safety so I'm ok with typecasts.

I've tried this:

let rec makeProperSucc (a : Succ<'a>) = Succ(makeProperNum Unchecked.defaultof<'a>)

and makeProperNum (obj : obj) : obj = 
    if obj :? Zero then Zero :> obj
    else makeProperSucc (obj :?> Succ<obj>) :> obj

let instance<'a>() = makeProperNum Unchecked.defaultof<'a> :?> 'a

Which doesn't work because defaultof gives me a null and all the type information is lost because I send it to a function expecting obj.

1

1 Answers

3
votes

What about defining a static member with static constraints in the DU?

Here's a quick draft with a unary operator:

type Zero = Zero with
    static member (!!) Zero = Zero

type Succ<'a> = Succ of 'a with
    static member inline (!!) (Succ a) = Succ (!!a)

// Test
!!(Unchecked.defaultof<Succ<Succ<Succ<Zero>>>>)
// val it : Succ<Succ<Succ<Zero>>> = Succ (Succ (Succ Zero))

I used an operator to keep it simple, but you can also write the static constraints by hand or use the inline helper as you did before in your previous question.

UPDATE

If you want to use the inline helper module, used in FsControl 1.x, you can do it this way:

type Instance = Instance with
    static member        instance(Instance, _:unit    ) = fun () -> ()
    static member        instance(Instance, _:Zero    ) = fun () -> Zero
    static member inline instance(Instance, _:Succ<'b>) = fun () -> 
        Succ (Inline.instance Instance ())

let inline instance() = Inline.instance Instance ()

let test:Succ<Succ<Zero>> = instance()

If you want to use the notation instance<'t>() you will have to disable the warning.