简体   繁体   中英

F# Compilation error with nested generics

I have a simple wrapper that I use to add aditional data to an arbitrary object:

type Wrapper<'T>(data:'T) =
  member val Data:'T=data with get
  member val AdditionalProperty:int=0 with get

Then I use those elements in a singly linked list, where I want to constraint the items to be of Wrapper<'T> , the elements are defined:

type LListItem<'T>(data:Wrapper<'T>) =
  member val Data:Wrapper<'T>=data with get
  member val Prev:LListItem<'T> option = None with get, set

And then I pretend to manage the linked list with this class:

 1| type LList<'T>()=
 2|   let mutable last:LListItem<Wrapper1<'T>> option = None
 3|   member x.Append(wrapped:Wrapper1<'T>)=
 4|     let item = new LListItem<'T>(wrapped)
 5|     match last with
 6|     | None -> 
 7|       last <- Some item
 8|     | Some l -> 
 9|       item.Prev <- last
10|      last <- Some item

But in this Append method, I these compilation errors:

  • Line 1 :This type parameter has been used in a way that constrains it to always be 'Wrapper<'T>'

  • Line 1 :This code is less generic than required by its annotations because the explicit type variable 'T' could not be generalized. It was constrained to be 'Wrapper<'T>'.

  • Line 3 :The generic member 'Append' has been used at a non-uniform instantiation prior to this program point. Consider reordering the members so this member occurs first. Alternatively, specify the full type of the member explicitly, including argument types, return type and any additional generic parameters and constraints.

I am doing something fundamentally wrong here, but I don't understand the compiler messages.

You are getting the error message, because the type inference somehow infers that the generic type parameter 'T is always constrained to be Wrapper<'T> . This usually happens when you have some code that takes a value of type 'T and passes it somewhere where Wrapper<'T> is expected.

In your case, this happens when you're setting last in the LList type. The type annotation defines that the type is LListItem<Wrapper<'T>> option :

type LList<'T>()=
  let mutable last:LListItem<Wrapper<'T>> option = None

But when you are assigning the value, the argument is LListItem<'T> . So you need to change the above line to this:

type LList<'T>()=
  let mutable last:LListItem<'T> option = None

I suspect that LListItem<Wrapper<'T>> is an error because LListItem always takes wrapped arguments.

EDIT : The other option to fix this is to change LListItem so that it never takes wrapped arguments - which is what Gustavo's answer suggests.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM