2015-05-15 16 views
5

Weź tę funkcję jako przykład:Jak ustawić domyślną wartość argumentu w F #?

// 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 

randomSequence Funkcja przyjmuje dwa argumenty: m, n. Działa to dobrze jak normalna funkcja. Chciałbym ustawić domyślne dla m, n, na przykład:

(m = 1, n = 100) 

gdy nie ma argumenty podane, funkcja ma wartość domyślną. Czy to możliwe w F #?

+1

Jest nieco trudne z powodu currying. –

Odpowiedz

6

często można achieve the same effect as overloading with a Discriminated Union.

Oto propozycja opiera się na OP:

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) } 

Wskazówka wprowadzenie Range dyskryminowanych Unii.

Oto kilka (FSI) przykłady użycia:

> 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] 

Innym rozwiązaniem jest zmiana randomSequence kiedykolwiek tak lekko wziąć krotki zamiast dwóch wartości:

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

Umożliwi to również zdefiniowanie domyślnej wartości :, podobnej do następującej:

let DefaultRange = 1, 100 

Oto kilka (FSI) przykłady użycia:

> 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

Wywołanie funkcji typu 'Between (x, y)' i 'Default' jest uciążliwe; ale to prawie najlepsze rozwiązanie. Dziękuję Ci! – Nick

+2

@Nick Być może jest to uciążliwe, ale czasami, z mojego doświadczenia, zmiana w dyskryminowanej Unii może wywołać nowe spostrzeżenia na temat domeny, a nowa dyskryminowana Unia może być również wykorzystywana w innych funkcjach, jak [ilustruje to związany przykład] (http://blog.ploeh.dk/2013/10/21/replace-overloading-w-discriminated-unions). W każdym razie, zaktualizowałem swoją odpowiedź z inną alternatywą. –

+0

Dziękuję bardzo. Właściwie w Pythonie lub R zwykłym sposobem wywoływania tej funkcji jest: (1) 'randomSequence (8, 39)', (2) 'randomSequence (39)', (3) 'randomSequence()'. Proszę zwrócić uwagę, że drugie połączenie jest równoznaczne z 'randomSequence (1, 39)'. W trzecim wywołaniu niczego nie sprecyzowałem - po prostu opróżnij '()'. – Nick

6

opcjonalne parametry są dozwolone tylko na członków [...]

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

Więc dla bieżącej przykład, myślę, że jest to niemożliwe. Ale można owinąć funkcjonalność:

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)) 

a następnie używać go tak:

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

wyjaśnienie: opcjonalne parametry mogą być albo całkowicie Opcja al (m) lub defaultArg s (n). Lubię cienie (ponowne używanie tej samej nazwy) tych parametrów, ale to jest dyskusyjne.

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

let randomSequenceWithDefaults() = 
    randomSequence 1 100 

Więc zamiast zadzwonić randomSequenceWithDefaults()

1

To wydaje się być najbardziej eleganckie rozwiązanie tego problemu:

//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

Powiązane problemy