2017-08-14 1 views
1

Ich schreibe meine eigene Version der Writer Monade, für Selbstbildung. Ich versuche, eine gewisse Allgemeinheit zu haben (aber ich versuche nicht, dies vollständig über statisch aufgelöste Typparameter oder andere Problemumgehungen zu erreichen).F # Static Member, Instanziierung des generischen Typs fehlt - möglicher Fehler?

Meine erste Version bekommt eine Warnung:

type Writer<'w, 'a> = | Writer of 'a * List<'w> with 

    static member sum (l1:'w list) (l2: 'w list) = l1 @ l2 

[<AutoOpen>] 
module WriterMonadMod = 

    module Writer = 
     let apply (mf:Writer<'w, ('a -> 'b)>) (ma:Writer<'w, 'a>) : Writer<'w, 'b> = 
      let (Writer (f, l1)), (Writer (a, l2)) = (mf, ma)  
      let b = f a 
      Writer (b, Writer.sum l1 l2) // Warning, on "Writer.sum", 
//Instantiation of generic type missing, can't be inferred. 

Okay, das macht Sinn. Welche statische Summe wollen wir? Für welche bestimmten Arten von Writer? Ich weiß nicht, ob ich diese Warnung ignorieren kann oder ob sie mich schließlich beißen könnte. Also versuche ich auf „Writer“ vor „.sum“ eine Art Argument zu setzen - aber jetzt, verursacht einen Fehler:

  Writer (b, Writer<'w, 'b>.sum l1 l2) //Error, on "<'w, 'b>", 
//unexpected type arguments. 

Das verwirrt mich, weil es wie die Syntax in einer anderen sieht so beantworten für Why can't F# infer the type in this case? (Cell<float>.Create 1.0 ; das funktioniert für mich, kein Fehler, keine Warnung und das Versuchen von nicht-generischen Typen ändert mein Problem nicht.)

So herumalbern ich mit Namen, unterscheidet den Typ von seinem Wert Konstruktor und fügt "T" hinzu - und jetzt behebt es iself !:

type WriterT<'w, 'a> = | Writer of 'a * List<'w> with 
//... 
    static member sum (l1:'w list) (l2: 'w list) = l1 @ l2 

[<AutoOpen>] 
module WriterMonadMod = 

    module WriterT = 
     let apply (mf:WriterT<'w, ('a -> 'b)>) (ma:WriterT<'w, 'a>) : WriterT<'w, 'b> = 
      let (Writer (f, l1)), (Writer (a, l2)) = (mf, ma)  
      let b = f a 
      Writer (b, WriterT<'w, 'b>.sum l1 l2) //No warning, no error. 
//(With "T" distinguishing the type name from value constructor.) 

Tut th macht Sinn? Warum scheint die übliche Praxis, denselben Namen für Typ und Konstruktor zu verwenden, hier eine Zweideutigkeit zu verursachen?

(Side Hinweise: „T“ ist keine gute Wahl, die ich denke, da dies keine Monade Transformator Und der Grund für alle Typenannotationen auf anzuwenden war, zu debuggen..)

Aktualisierung aufgrund Tomas Antwort:

Seltsamerweise funktioniert das auch, um den Fehler und die Warnung zu vermeiden. Whildcards dienen zur Auflösung der Ambiguität Warnung !?

module WriterT = 
     let apply (mf:WriterT<_,_>) (ma:WriterT<_,_>) : WriterT<_,_> = 
      let (Writer (f, log1)), (Writer (a, log2)) = (mf, ma)  
      let b = f a 
      Writer (b, WriterT<_,_>.sum log1 log2)  

Antwort

2

Der Fehler "unerwartete Art Argumente" im zweiten Fall ist sehr verwirrend (vielleicht sogar ein Fehler). Ich denke, was hier passiert ist, dass der Compiler zuerst Writer als den Fallnamen auflöst und dann den Fehler meldet, wenn er die Typargumente findet. Es stellt dann fest, dass Sie sich tatsächlich auf einen Typ beziehen und den Plan ändern. Das Umbenennen des Typs (in Ihrem letzten Beispiel) behebt diese Mehrdeutigkeit.

Eine weitere Möglichkeit, dieses Problem zu lösen ist das RequireQualifiedAccess Attribut hinzufügen, die die Vereinigung Fall hinter dem Typnamen verstecken, so müssen Sie Writer.Writer und der erste Name bezieht sich auf die Art schreiben:

[<RequireQualifiedAccess>] 
type Writer<'w, 'a> = | Writer of 'a * List<'w> with  
    static member sum (l1:'w list) (l2: 'w list) = l1 @ l2 

module Writer = 
    let apply (mf:Writer<'w, ('a -> 'b)>) (ma:Writer<'w, 'a>) : Writer<'w, 'b> = 
     let (Writer.Writer (f, l1)), (Writer.Writer (a, l2)) = (mf, ma)  
     let b = f a 
     Writer.Writer (b, Writer<_,_>.sum l1 l2) 

Jetzt Sie können Writer<_, _>.sum eingeben, und es funktioniert, weil die Typenreferenz aufgelöst wird.

+0

Danke für die Suche nach Tomas. Ich schätze, ich sollte einen Vorschlag einreichen. Und das scheint eine gute Gelegenheit für mich zu sein, selbst in den Compiler zu schauen und zu sehen, ob ich das selbst debuggen kann, was ich versuchen wollte zu lernen. – RomnieEE

+0

Nun scheint es mir in Ihrem Code: dass die Warnung Unfähigkeit, den Writer-Typ für statische ".sum" abzuleiten geht mit einem _wild Card_ Typ Annotation!? Ich sehe, dass das Ändern aller Typenargumente auf "WriterT" zu "<_,_>" in "apply" die Warnung immer noch vermeidet. Es scheint seltsam, dass Wildcards eine Mehrdeutigkeit reparieren können. Aber vielleicht liegt es daran, dass ich nicht wirklich verstehe, wie Typinferenz funktioniert. – RomnieEE

Verwandte Themen