2012-04-10 5 views
6

Um eine Folge von meiner Klasse zu erstellen,F # - Kann ich den Typnamen als Funktion verwenden, die als Standardkonstruktor fungiert?

type MyInt(i:int) = 
    member this.i = i 

[1;2;3] |> Seq.map(fun x->MyInt(x)) 

wo fun x->MyInt(x) überflüssig zu sein scheint. Es wäre besser wenn ich schreiben könnte Seq.map(MyInt)

Aber ich kann nicht. Eine Abhilfe, die ich denken kann, ist eine separate Funktion zu definieren

let myint x = MyInt(x) 
[1;2;3] |> Seq.map(myint) 

Gibt es einen besseren Weg, dies zu tun?

Antwort

7

Kurz gesagt, nein.

Objektkonstruktoren sind keine erstklassigen Funktionen in F #. Dies ist ein weiterer Grund, nicht-Klassen zu verwenden, diskriminiert Gewerkschaften besser ist hier zu verwenden:

type myInt = MyInt of int 
let xs = [1;2;3] |> Seq.map MyInt 

Wenn Sie explizite lambdas nicht gefällt, Sequenz Ausdruck sieht schöner in Ihrem Beispiel:

let xs = seq { for x in [1;2;3] -> MyInt x } 

Alternativ Ihre Workaround ist eine nette Lösung.

9

Wenn unentgeltlichen Hacks Sie nicht die Mühe machen, könnten Sie tun:

///functionize constructor taking one arg 
let inline New< ^T, ^U when ^T : (static member ``.ctor`` : ^U -> ^T)> arg = 
    (^T : (static member ``.ctor`` : ^U -> ^T) arg) 

type MyInt(i: int) = 
    member x.i = i 

[0..9] |> List.map New<MyInt, _> 

EDIT: Wie kvb wies darauf hin, eine einfachere (und weniger hacky) Signatur verwendet werden können:

let inline New x = (^t : (new : ^u -> ^t) x) 

Beachten Sie, dass der Typ args umschaltet, so dass es New<_, MyInt> wird.

+0

Ihre Definition von 'New' kompiliert für mich in der VS11 Beta nicht. Eine einfachere Variante heißt jedoch: 'lass Inline New x = (^ t: (neu:^u ->^t) x)'. – kvb

+0

Ich habe das zuerst versucht, aber mit expliziten Einschränkungen '^ t wenn^t: (neu:^u ->^t) 'was in VS2010 nicht kompiliert wird. Freut mich zu wissen, dass es einen einfacheren Weg gibt, dies zu tun. – Daniel

+0

Seltsamerweise unterstützt der Compiler nur explizite Constructor-Constraints der Form 'new: unit -> 't' (die direkt in .NET-Metadaten dargestellt werden können), aber Sie können offensichtlich general constructor constraint _invocation expressions_ verwenden und den Compiler auf die Constraints schließen lassen . Es ist definitiv ein kleines Loch im System. – kvb

0

Ich verwende statische Methoden für diesen Zweck. Der Grund dafür ist, dass manchmal Ihr Objektkonstruktor zwei Argumente aus unterschiedlichen Quellen stammen muss, und mein Ansatz ermöglicht es Ihnen List.map2 verwenden:

type NumRange(value, range) = 
    static member Make aValue aRange = new NumRange(aValue, aRange) 

let result1 = List.map2 NumRange.Make values ranges 

Teil Anwendung nicht auch verboten:

let result2 = 
    values 
    |> List.map NumRange.Make 
    |> List.map2 id <| ranges 

Wenn Sie nicht mögen mit id hier können Sie (fun x y -> x y) verwenden, die besser lesbar ist.

1

Um ein Update zu diesem Thema - F# 4.0 hat Konstruktoren zu erstklassigen Funktionen aktualisiert, so dass sie jetzt überall dort, wo eine Funktion oder Methode verwendet werden kann.

Verwandte Themen