2015-01-30 5 views
7

Wie kann ich (wenn alle at) variadische Funktionen emulieren (diese Methoden nicht), so dass ichWie schreibt man eine Variadic-Funktion in F #, die eine ähnliche Haskell-Lösung emuliert?

sum 1 2 3 
sum 1 2 3 4 5 
sum 1 2 3 4 5 6 7 
// etc. 

Der obige Code nur als Beispiel gemeint schreiben könnte - natürlich, wenn ich zusammenfassen müsste bis eine Liste dann

[ 1; 2 ; 3] |> List.sum 

ist ein viel besserer Weg.

Jedoch habe ich für eine strukturell ähnliche Lösung suchen, wie this Haskell solution

Was auch wichtig ist, ist, dass die normale Syntax für Funktionsaufrufe und Parameterwerte gleich bleibt. So

sum 1 2 3 

vs

sum(1, 2, 3) 

die effektiv bedeutet, dass

let sum ([<ParamArray>] arr) = ... 

nicht in diesem speziellen Fall wird gesucht.

Die Motivation für all dies: Ich untersuche die äußeren Ränder von F # 's Typ System und Syntax. Und ich bin mir vollkommen bewusst, dass ich die Grenze dessen, was bereits möglich ist, überschritten haben könnte.

PS: Meine konkreten Ideen (die ich hier nicht beschrieben habe) können auch ganz anders gelöst werden - also weiß ich es und so habe ich es schon gemacht. Deshalb ist meine Frage nicht: wie kann das anders gelöst werden, aber wie kann das strukturell wie Haskell gelöst werden?

PPS: Doppelte Karma-Punkte, wenn Sie die gesamte Lösung rekursiv machen können.

+2

Siehe Parameter-Arrays hier: https://msdn.microsoft.com/en-us/library/dd233213.aspx –

+3

möglich Duplikat von [Wie schreibe ich eine Funktion, die variable Anzahl von Argumenten in F #] (http: // stackoverflow .com/fragen/674319/howto-write-a-function-nehmen-Variable-Anzahl-von-Argumenten-in-f) – scrwtp

+0

@scrwtp: Ich habe die Frage erweitert. Ich hoffe, es ist jetzt noch klarer, dass dies keine doppelte Frage ist. Zumindest nicht zu deinem Link. – robkuz

Antwort

18

Sie sagten Funktion, nicht Methode. Also ParamArray ist keine Option.

Der von Ihnen verknüpfte Haskell-Code basiert auf dem abgeleiteten Ergebnistyp.

Hier ist eine Art und Weise auf der Grundlage der abgeleiteten Ergebnistyp in F # zu beheben:

type T = T with 
    static member inline ($) (T, r:'t->'t  ) = fun a b  -> a + b 
    static member inline ($) (T, r:'t->'t->'t ) = fun a b c -> a + b + c 
    static member inline ($) (T, r:'t->'t->'t->'t) = fun a b c d -> a + b + c + d 

let inline sum (x:'a) :'r = (T $ Unchecked.defaultof<'r>) x 

let x:int = sum 2 3 
let y:int = sum 2 3 4 
let z:int = sum 2 3 4 5 
let d:decimal = sum 2M 3M 4M 

let mult3Numbers a b c = a * b * c 
let res2 = mult3Numbers 3 (sum 3 4 ) 10 
let res3 = mult3Numbers 3 (sum 3 4 5) 10 

UPDATE

Und hier ist eine rekursive polyvariadic Funktion nimmt n (unbegrenzt) Argumente:

type T = T with 
    static member  ($) (T, _:int ) = (+) 
    static member  ($) (T, _:decimal) = (+) 

let inline sum (i:'a) (x:'a) :'r = (T $ Unchecked.defaultof<'r>) i x 

type T with 
    static member inline ($) (T, _:'t-> 'rest) = fun (a:'t) -> (+) a >> sum 


let x:int = sum 2 3 
let y:int = sum 2 3 4 
let z:int = sum 2 3 4 5 
let d:decimal = sum 2M 3M 4M 

let mult3Numbers a b c = a * b * c 
let res2 = mult3Numbers 3 (sum 3 4) (sum 2 2 3 3) 
let res3 = mult3Numbers 3 (sum 3 4 5 11 13 20) 10 

Sie können sich auch diese polyvariadic fold ansehen.

+0

Nicht sicher, warum dies abgelehnt wurde, weil es * die * Frage beantwortet. Obwohl ich denke, das funktioniert nur für eine bestimmte Anzahl von Überladungen, oder? (Ich würde nicht empfehlen F # auf diese Weise zu schreiben, aber das ist ein separates Thema.) –

+0

Ich verstehe auch nicht, warum das heruntergeregelt wurde. Sofar die beste Antwort UND wenn ich das so sagen darf der einzige, der meine (erste) Frage gelesen hat ;-) – robkuz

+0

@gustavo: Kannst du das auch rekursiv machen? – robkuz

5

Wie in den Kommentaren erwähnt, können Sie das Attribut ParamArray in F # verwenden, damit Sie die Funktion mit mehreren Parametern aufrufen können - obwohl Sie die .NET-Notation verwenden und sum(1,2,3,4,5,6) schreiben müssen.

Das sagte, würde ich wahrscheinlich nicht in der Praxis tun. Wenn Sie eine Funktion schreiben, welcher eine Eingabe aus einer unbekannten Anzahl von Werten erfolgt, dann eine Liste mit wahrscheinlich ein besseres Design:

List.sum [1; 2; 3 ] 
List.sum [1; 2; 3; 4; 5 ] 
List.sum [1; 2; 3; 4; 5; 6; 7 ] 

Dies ist nur ein paar Zeichen und es bessere Modelle das Problem, dass Sie lösen - zumindest basierend auf dem Spielzeugbeispiel, das Sie hier gepostet haben.

Es ist schwer, eine gute Antwort zu geben, ohne zu wissen, was das Problem ist, das Sie tatsächlich lösen. Aber im Allgemeinen denke ich, dass das Aufnehmen einer Liste ein guter F # -freundlicher Standard ist. Die Verwendung von ParamArray ist in einigen Fällen und für C# Interop nützlich.

+3

@robkuz Als "die Grenzen des F # -Typ Systems zu erkunden", ist dies sinnvoll. Trotzdem denke ich, dass es wichtig ist zu sagen, dass niemand das wirklich in der Praxis tun sollte :-). Dies ist besonders der Fall bei Fragen wie "Wie kann ich XYZ von Haskell in F # machen", weil sie oft Menschen in eine falsche Richtung weisen (blind Techniken aus einer Sprache in einer anderen Sprache zu benutzen ist nie eine gute Idee). Natürlich sind reine Fragen, die außerhalb der Neugier liegen, eine Ausnahme! –

Verwandte Themen