2015-12-23 12 views
6

ho definito il seguente tipo (semplificato dal codice):inferenza di tipo in mancanza del tipo generico con vincolo membro statico

type Polynomial<'a when 'a :(static member public Zero : 'a) 
       and 'a: (static member (+): 'a*'a -> 'a) 
       and 'a : (static member (*): 'a*'a -> 'a) > = 
    | Polynomial of 'a list 
    with 
    static member inline (+) (x: Polynomial<'a> , y : Polynomial<'a>) : Polynomial<'a>= 
     match x,y with 
     |Polynomial xlist, Polynomial ylist -> 
      let longer, shorter = 
       if xlist.Length> ylist.Length then xlist, ylist 
       else ylist, xlist 
      let shorterExtended = List.append shorter (List.init (longer.Length - shorter.Length) (fun _ -> LanguagePrimitives.GenericZero<'a>)) 
      List.map2 (+) longer shorterExtended |> Polynomial 

Quando costruisco ottengo l'avvertimento: FS0193

avvertimento: A parametro di tipo manca un vincolo 'quando (^ a oppure^23604?): (static> membro (+):??^a *^23604 ->^23605)'

sulla parola "più" nell'ultima riga. Per quanto posso vedere dovrebbe essere in grado di dedurre che si aggiungono sempre due membri di 'a. Come posso sbarazzarmi di questo?

risposta

3

Questa è una domanda interessante, utilizzando una funzione associata let invece di un membro statico non sembra attivare lo stesso avviso. Presumibilmente ci sono differenze tra la risoluzione dei parametri di tipo statico nelle funzioni let bound e member.

module PolyAdder = 
    let inline addPoly x y = 
     match x,y with 
     |Polynomial xlist, Polynomial ylist -> 
      let (longer : ^a list), (shorter : ^a list) = 
       if xlist.Length > ylist.Length then xlist, ylist 
       else ylist, xlist 
      let shorterExtended : ^a list = shorter @ (List.init (longer.Length - shorter.Length) (fun _ -> LanguagePrimitives.GenericZero<^a>)) 
      // no warning here! 
      List.map2 (+) longer shorterExtended |> Polynomial 

È quindi possibile estendere Polynomial con un operatore + in base alla let funzione legata sopra:

type Polynomial with 
    static member inline (+) (x, y) = PolyAdder.addPoly x y 

non c'è ancora avvertimento e l'operatore + funziona normalmente

let poly1 = [1; 2; 5; 6; 8] |> Polynomial 
let poly2 = [7; 1; 2; 5;] |> Polynomial 
let polyAdded = poly1 + poly2 
+0

Nizza soluzione . – FZed