2015-05-15 12 views
5

Nehmen Sie diese Funktion als Beispiel:Wie Standard-Argument-Wert in F # festlegen?

// Sequence of random numbers 
open System 

let randomSequence m n= 
    seq { 
     let rng = new Random() 
     while true do 
      yield rng.Next(m,n) 
    } 


randomSequence 8 39 

Die randomSequence Funktion nimmt zwei Argumente: m, n. Dies funktioniert wie eine normale Funktion. Ich mag die Standardeinstellung für m, n, zum Beispiel:

(m = 1, n = 100) 

Wenn es keine Argumente angegeben, nimmt die Funktion den Standardwert. Ist das in F # möglich?

+1

Dies ist etwas tricky wegen currying. –

Antwort

6

Sie können oft achieve the same effect as overloading with a Discriminated Union.

Hier ist ein Vorschlag auf dem OP basiert:

type Range = Default | Between of int * int 

let randomSequence range = 
    let m, n = 
     match range with 
     | Default -> 1, 100 
     | Between (min, max) -> min, max 

    seq { 
     let rng = new Random() 
     while true do 
      yield rng.Next(m, n) } 

Beachten Sie die Einführung der Range diskriminierter Union.

Hier sind einige (FSI) Anwendungsbeispiele:

> randomSequence (Between(8, 39)) |> Seq.take 10 |> Seq.toList;; 
val it : int list = [11; 20; 36; 30; 35; 16; 38; 17; 9; 29] 

> randomSequence Default |> Seq.take 10 |> Seq.toList;; 
val it : int list = [98; 31; 29; 73; 3; 75; 17; 99; 36; 25] 

Eine weitere Option ist die randomSequence immer so leicht ein Tupel statt zwei Werte zu annehmen zu ändern:

let randomSequence (m, n) = 
    seq { 
     let rng = new Random() 
     while true do 
      yield rng.Next(m, n) } 

Damit können Sie auch einen Standardwert wie folgt definieren:

Hier sind einige (FSI) Anwendungsbeispiele:

> randomSequence (8, 39) |> Seq.take 10 |> Seq.toList;; 
val it : int list = [30; 37; 12; 32; 12; 33; 9; 23; 31; 32] 

> randomSequence DefaultRange |> Seq.take 10 |> Seq.toList;; 
val it : int list = [72; 2; 55; 88; 21; 96; 57; 46; 56; 7] 
+0

Eine Funktion mit dem Typ 'Between (x, y)' 'und' Default' aufzurufen, ist umständlich; aber das ist fast die beste Lösung. Vielen Dank! – Nick

+2

@Nick Vielleicht ist es beschwerlich, aber manchmal kann der Wechsel zu einer diskriminierten Union nach meiner Erfahrung neue Einsichten über den Bereich eröffnen, und die neue diskriminierte Union kann auch in anderen Funktionen verwendet werden, wie [das verlinkte Beispiel] (http://blog.ploeh.dk/2013/10/21/replace-overloading-with-discriminated-unions). Jedenfalls habe ich meine Antwort mit einer anderen Alternative aktualisiert. –

+0

Vielen Dank. In Python oder R ist der übliche Weg diese Funktion aufzurufen: (1) 'randomSequence (8, 39)', (2) 'randomSequence (39)', (3) 'randomSequence()'. Bitte beachten Sie, dass der zweite Aufruf gleich 'randomSequence (1, 39)' ist. Und im dritten Aufruf habe ich nichts angegeben - einfach leer '()'. – Nick

6

Optionale Parameter sind nur gestattet, auf Mitglieder [...]

https://msdn.microsoft.com/en-us/library/dd233213.aspx

Also, für Ihr aktuelles Beispiel, ich denke, es ist unmöglich. Aber man könnte die Funktionalität wickeln:

type Random = 
    static member sequence(?m, ?n) = 
     let n = defaultArg n 100 
     let rng = new System.Random() 
     match m with 
     | None -> Seq.initInfinite (fun _ -> rng.Next(1, n)) 
     | Some(m) -> Seq.initInfinite (fun _ -> rng.Next(m, n)) 

und dann verwenden Sie es wie folgt aus:

let randomSequence = Random.sequence(2, 3) 
let randomSequence' = Random.sequence(n = 200) 
let randomSequence'' = Random.sequence() 

Erläuterung: optionale Parameter können entweder al voll Option sein (m) oder defaultArg s (n). Ich mag Shadowing (Wiederverwendung des gleichen Namens) diese Parameter, aber das ist fraglich.

3
let randomSequence m n= 
    seq { 
    let rng = new Random() 
    while true do 
     yield rng.Next(m,n) 
    } 

let randomSequenceWithDefaults() = 
    randomSequence 1 100 

Also statt, rufen randomSequenceWithDefaults()

1

Dies scheint die eleganteste Lösung für dieses Problem zu sein:

//define this helper function 
let (|Default|) defaultValue input = 
    defaultArg input defaultValue 

//then specify default parameters like this 
let compile (Default true optimize) = 
    optimize 

//or as the OP asks 
let randomSequence (Default 1 m) (Default 100 n) 
    seq { 
     let rng = new Random() 
     while true do 
      yield rng.Next(m,n) 
    } 

Credits: http://fssnip.net/5z