Domanda

Sto cercando di capire come definire una funzione che funziona su più tipi di parametri (ad esempio int e Int64). A quanto mi risulta, l'overloading di funzioni non è possibile in F # (certamente il compilatore si lamenta). Prendiamo ad esempio la seguente funzione.

let sqrt_int = function
    | n:int   -> int (sqrt (float n))
    | n:int64 -> int64 (sqrt (float n))

Il compilatore, naturalmente, si lamenta che la sintassi non è valida (tipo vincoli nel pattern matching non sono supportate a quanto pare), anche se penso che questo illustra ciò che vorrei realizzare: una funzione che opera su diversi tipi di parametri e restituisce un valore del tipo secondo. Ho la sensazione che questo è possibile in F # utilizzando una combinazione di tipi generici / tipo di corrispondenza di inferenza / modello, ma la sintassi mi ha eluso. Ho anche provato ad utilizzare il:? operatore (prove di tipo dinamico) e quando clausole del pattern matching blocco, ma ancora produce errori ordinamenti.

Come io sono piuttosto nuovo per la lingua, mi può benissimo essere cercando di fare qualcosa di impossibile qui, quindi per favore fatemi sapere se v'è soluzione alternativa.

È stato utile?

Soluzione

Il sovraccarico è in genere lo spauracchio dei linguaggi di tipo-inferenced (almeno quando, come F #, il sistema di tipo non è abbastanza potente per contenere tipo-classi). Ci sono una serie di scelte che avete in F #:

  • Usa sovraccarico sui metodi (membri di tipo A), nel qual caso sovraccarico opere molto simile a come in altri linguaggi .NET (è possibile membri di sovraccarico ad hoc, a condizione chiamate può essere distinto dal numero / tipo di parametri)
  • Usa "in linea", "^", e vincoli membri statici per ad-hoc sovraccaricando sulle funzioni (questo è ciò che la maggior parte dei vari operatori matematici che hanno bisogno di lavorare su int / float / etc .; la sintassi qui è strano , questo è poco utilizzata a parte la libreria F #)
  • Simula classi di tipo passando un parametro aggiuntivo dizionario-di-operazioni (questo è ciò che INumeric fa in una delle biblioteche # PowerPack F generalizzare vari algoritmi matematici per i tipi definiti dall'utente arbitrari)
  • ricadere a tipizzazione dinamica (passare in un parametro 'obj', fare un test di tipo dinamico, un'eccezione di runtime per il tipo cattivo)

Per la vostra esempio particolare, probabilmente basta usare overloading dei metodi:

type MathOps =
    static member sqrt_int(x:int) = x |> float |> sqrt |> int
    static member sqrt_int(x:int64) = x |> float |> sqrt |> int64

let x = MathOps.sqrt_int 9
let y = MathOps.sqrt_int 100L

Altri suggerimenti

Questo funziona:

type T = T with
    static member ($) (T, n:int  ) = int   (sqrt (float n))
    static member ($) (T, n:int64) = int64 (sqrt (float n))

let inline sqrt_int (x:'t) :'t = T $ x

Si utilizza vincoli statici e sovraccarico, che fa una ricerca al momento della compilazione del tipo dell'argomento.

I vincoli statici vengono generati automaticamente in presenza di un operatore (operatore $ in questo caso), ma può sempre essere scritti a mano:

type T = T with
    static member Sqr (T, n:int  ) = int   (sqrt (float n))
    static member Sqr (T, n:int64) = int64 (sqrt (float n))

let inline sqrt_int (x:'N) :'N = ((^T or ^N) : (static member Sqr: ^T * ^N -> _) T, x)

Ulteriori su questi qui .

Sì, questo può essere fatto. Date un'occhiata a questa discussione hubFS .

In questo caso, la soluzione potrebbe essere:

let inline retype (x:'a) : 'b = (# "" x : 'b #)
let inline sqrt_int (n:'a) = retype (sqrt (float n)) : 'a

Caveat : nessun tipo in fase di compilazione controllo. Cioè sqrt_int "blabla" compila bene, ma si otterrà una FormatException in fase di esecuzione.

Ecco un altro modo con controlli di tipo runtime ...

let sqrt_int<'a> (x:'a) : 'a = // '
    match box x with
    | :? int as i -> downcast (i |> float |> sqrt |> int |> box)
    | :? int64 as i -> downcast (i |> float |> sqrt |> int64 |> box)
    | _ -> failwith "boo"

let a = sqrt_int 9
let b = sqrt_int 100L
let c = sqrt_int "foo" // boom

Per non togliere le risposte corrette già previsti, ma si può, infatti, di tipo uso vincoli nel pattern matching. La sintassi è:

| :? type ->

Se si desidera combinare controllo dei tipi e casting:

| :? type as foo ->
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top