Auf meiner Suche nach besserem F # und einem besseren Verständnis der Funktionsweise von Suave.io habe ich versucht, einige wiederverwendbare Funktionen/Operatoren für das Erstellen von Funktionen zu erstellen . Ich verstehe, dass Suave tatsächlich seinen> => Operator implementiert, um speziell für asynchrone Optionen zu arbeiten, aber ich dachte, es würde mir Spaß machen, es zu verallgemeinern.Statisch aufgelöste Typen Member Constraints erkennen Erweiterungen von Systemtypen nicht
Der unten stehende Code ist von zu vielen Quellen zu kreditieren, und es funktioniert gut für Typen, die ich selbst definiere, aber ich kann es nicht für Systemtypen arbeiten lassen. Obwohl die Typenerweiterungen von Nullable und Option gut kompiliert werden, werden sie nicht als übereinstimmend mit der Memberbeschränkung in der Bindungsfunktion erkannt.
Als ich es versäumt habe, es für Option zu machen, hatte ich gehofft, dass es daran liegen könnte, dass Option in F # speziell ist, weshalb ich mit Nullable versuchte, aber leider keine Zigarre.
Die relevanten Fehler und Ausgabe von FSI ist in dem Code unten im Kommentar.
Jede Hilfe wäre willkommen.
Danke, John
open System
let inline bind (f : ^f) (v : ^v) =
(^v : (static member doBind : ^f * ^v -> ^r)(f, v))
// I'd prefer not having to use a tuple in doBind, but I've
// been unable to make multi arg member constraint work
let inline (>=>) f g = f >> (bind g)
// Example with Result
type public Result<'a,'b> =
| Success of 'a
| Error of 'b
type public Result<'a,'b> with
static member inline public doBind (f, v) =
match v with
| Success s -> f s
| Error e -> Error e
let rF a = if a > 0 then Success a else Error "less than 0"
let rG a = if a < 10 then Success a else Error "greater than 9"
let rFG = rF >=> rG
// val rFG : (int -> Result<int,string>)
//> rFG 0;;
//val it : Result<int,string> = Error "less than 0"
//> rFG 1;;
//val it : Result<int,string> = Success 1
//> rFG 10;;
//val it : Result<int,string> = Error "greater than 9"
//> rFG 9;;
//val it : Result<int,string> = Success 9
// So it works as expected for Result
// Example with Nullable
type Nullable<'T when 'T: (new : unit -> 'T) and 'T: struct and 'T:> ValueType> with
static member inline public doBind (f, v: Nullable<'T>) =
if v.HasValue then f v.Value else Nullable()
let nF a = if a > 0 then Nullable a else Nullable()
let nG a = if a < 10 then Nullable a else Nullable()
let nFG = nF >=> nG
// error FS0001: The type 'Nullable<int>' does not support the operator 'doBind'
type Core.Option<'T> with
static member inline doBind (f, v) =
match v with
| Some s -> f s
| None -> None
let oF a = if a > 0 then Some a else None
let oG a = if a < 10 then Some a else None
let oFG = oF >=> oG
// error FS0001: The type 'int option' does not support the operator 'doBind'
Erweiterungselemente werden für statisch aufgelöste Typabhängigkeiten nicht berücksichtigt. Nur kein Feature von F #, Punkt. [Bitte stimme über uservoice] ab (https://fslang.uservoice.com/forums/245727-f-language/suggestions/5664242-simulate-higher-kinded-polymorphism). –
Wie von Fjodor erwähnt, wird dies nicht unterstützt. Während ich denke, dass dies eigentlich eine schöne Erweiterung zu F # wäre, bin ich ziemlich neugierig, was für Anwendungsfälle Sie dafür hatten? Ich finde Suave nett, weil es ziemlich einfach und nicht übermäßig abstrakt ist, also verallgemeinern die Operatoren nicht wie etwas, das zu besserem F # Code gehen würde - obwohl es Spaß macht, es einfach zu erforschen, natürlich. –
@FyodorSoikin Danke, das erklärt es. Was für eine nervige Einschränkung, 3 Stimmen wurden abgegeben :) – JJJ