Limited type representation without using a class

In F #, can I represent a limited type without a class definition? Suppose I want to represent all pairs of numbers where the first divides the second.

in C # I could do:

class PairDivides { int a {get;private set;} int b {get;private set;} PairDivides(int first, int second) { if (a % b != 0) { throw new Exception(); } this.a = first; this.b = second; } } 

Now it is impossible to create an instance of PairDivides where b does not divide a ...

Is it possible to do this in F # using only functional constructs (recording, discriminatory union, possibly active templates, etc.)?

I want to be able to create and receive something like these pairs, being sure that they are built correctly.

+6
source share
1 answer

You can do this by making the type private. The only drawback is that you need to provide functions for accessing data:

 module Pairs = type PairDivides = private { a: int; b: int } let createPairDivides ab = match a % b with | 0 -> Some { PairDivides.a = a ; b = b } | _ -> None let print div = printfn "{%d %d}" div.a div.b let tryPrint div = match div with | Some a -> print a | None -> printfn "None" let a = Pairs.createPairDivides 2 2 let b = a.Value // This is inaccessible: ba Pairs.createPairDivides 2 2 |> Pairs.tryPrint Pairs.createPairDivides 2 3 |> Pairs.tryPrint 

By providing a function to create a pair and a function to use or retrieve it if necessary, you completely eliminate the possibility of creating invalid pairs (you get None back instead of a bad pair) without using exceptions.

The disadvantage is that you need to provide mechanisms for extracting values ​​from pairs, since this type is now unavailable when used outside of your current module.

Having said that, there is nothing wrong with doing this through classes. You can get the same level of enforcement by creating a class if you want:

 type PairDivides private (a,b) = member __.A = a member __.B = b static member Create ab = match a % b with | 0 -> Some(PairDivides(a,b)) | _ -> None PairDivides.Create 2 2 |> printfn "%A" PairDivides.Create 2 3 |> printfn "%A" 
+6
source

All Articles