Static Resolution Options

The following (simplified) fragment is taken from the application that I am implementing, which sequentially uses type parameters that are allowed statically.

type A< ^B when ^B : (static member MyMember : Unit -> Unit)> = { Field : unit } type TestA = { AField : A< BTy > } and BTy = { BField : Unit } with static member MyMember () = () 

IntelliSense gives me the following error when I determine the type of an AField field ( AField : A< BTy > ), which: Type "BTy" does not support operators named "MyMember" .

The editors. Declaring them separately works, but if I have a reciprocal link, and I can not declare a third type, which will be placed at the top, which contains general information of these two types. What should I do to avoid this problem? In any case, if I define below the definition of let pluto = ("" :> obj) :?> A< BTy > , this works, I think, because both types are visible from the let binding.

+4
types parameters f #
Oct. 14 '12 at 11:34
source share
2 answers

Your implementation of @Tomas satisfies the question, but there are some doubts about the style of your solution, because it does not adhere to the functional programming paradigm. I was thinking of a solution resulting from the implementation of Type Classes Haskell. Interfaces, abstract classes, etc. were implemented, so that the F # environment could "interact" with the .Net environment, due to the uniform style, the use of code that implements interfaces, abstract classes, etc. In a context where there is no need to interact with .Net libraries, this, in my opinion, is β€œOverhead” (although F # is a language with several paradigms). It is for this reason that I realized that the implementation of Type Classes Haskell is very elegant. Below I have implemented the "Haskell Type" code through F # to solve my problem.

 type Operations< ^a> = { MyMember : unit -> unit } type A< ^a> = { Operations : Operations< ^a> } and TestA = { AField : A< BTy > } and BTy = { BField : Unit } let it = let BTy_operations : Operations< BTy > = { MyMember = fun () -> () } let A_of_BTy = { Operations = BTy_operations } { AField = A_of_BTy } 
-one
Oct. 15
source share

Honestly, I'm a little surprised that you are even allowed to use static member constraints in a type declaration, but, as mentioned in @pad, when you place the ads in the correct order and delete the recursion, (although I'm not sure when moving to more complex examples will not have other restrictions):

 type A< ^B when ^B : (static member MyMember : Unit -> Unit)> = { Field : unit } type BTy = { BField : Unit } static member MyMember () = () type TestA = { AField : A<BTy> } 

In any case, I think using static member constraints in a type declaration is a bit more complicated. A cleaner way to do this is to define an interface that clearly describes (and documents) the members you need:

 type IMyMember = abstract MyMember : unit -> unit 

Now, static element constraints can still be used to create an implementation of an interface from a type that has the required element but does not implement the interface. Using this method, you should be able to implement the same functions as with the constraints of the static member on types (but in a more clear way):

 /// Captures 'IMyMember' implementation from another type using static constraints let inline captureMyMember< ^B when ^B : (static member MyMember : Unit -> Unit)> = { new IMyMember with member x.MyMember () = (^B : (static member MyMember : Unit -> Unit) ()) } 

The function, for example, will create IMyMember from your BTy type:

 /// A type that contains field and a captured implementation of 'IMyMember' type A = { Field : unit Operations : IMyMember } let it = { Field = () Operations = captureMyMember<BTy> } 

Also, I used the same technique in an article that shows how to write a generic digital code , and I think it worked really nicely there.

+11
Oct. 15
source share



All Articles