2014-10-31 12 views
5

Sono nuovo su F #. Stavo scherzando e ho trovato qualcosa di interessante e speravo che qualcuno potesse illuminarmi su cosa sta succedendo dietro lo scenario.Perché vengono passate le funzioni al primo tipo.

Così ho fatto la funzione: let my_func (x, y) = x + y.

Quindi ho chiamato la funzione con gli args 1 e 2 assegnandomi 3. Questo è quello che mi aspettavo che succedesse, ma quando ho passato due stringhe a my_func ho ricevuto un errore anche se + è un operatore valido con stringhe. Riesero a riattivare il mio codice ma stavolta solo chiamando my_func con "cat" e " dog" che mi ha dato "cat dog". Ho quindi provato a passare 1 e 2 di nuovo a my_func solo per scoprire che my_func non accetta più numeri interi.

Perché my_func si comporta in questo modo?

let my_func (x, y) = x + y
my_func (1, 2) // produces => 3
my_func ("cat", " dog") // Error

programma replica ...

let my_func (x, y) = x + y
my_func ("cat", " dog") // produces => "cat dog"
my_func (1, 2) // Error

risposta

8

@MarcinJuraszek vi ha mostrato come risolvere questo problema, ma non disse nulla riguardo perché accade.

si può pensare a come questo:

s 'F # inferenza di tipo lavora cima a fondo, sinistra a destra - in modo che quando il sistema tenta di trovare il tipo per my_func troverà assegnare i tipi di la prima riga in cui si utilizza la funzione (il primo esempio è int s e il secondo è string s) - Se non lo si usa affatto o lo si definisce in FSharp Interactive, verrà impostato automaticamente su int.

Dichiarare la funzione come inline consente F # da usare statically resolved type parameters (a causa di alcuni dettagli questo è possibile solo con inline funzioni) e poi sarà davvero fare qualcosa di simile che le esigenze di funzionalità anatra-digitando di capire dalla dichiarazione tipi in cui un operatore statico + viene definito in qualche modo.

Potete vedere questo nel tipo di funzione:

val inline my_func : 
    x: ^a * y: ^b -> ^c 
    when (^a or ^b) : (static member (+) : ^a * ^b -> ^c) 

questo tipo piuttosto complicato dice proprio questo:

Ci deve essere un operatore di statica (+) : ^a * ^b -> ^c su ^a (si pensi 'a) che viene utilizzato quando scrivi + nel corpo delle funzioni. Come puoi vedere, questo è ancora più generico di quanto tu ne abbia realmente bisogno, ma non è un problema. F # implementerà versioni concrete (con i tipi generici sostituiti) per sempre la presenza di questa funzione applicata (quindi nel tuo esempio ci saranno due istanze my_func nel tuo IL, una per Int s e una per String s) - ma questo ha vinto ' Non ti dà fastidio in fase di progettazione.

Così ora avete una più generica funzione che può essere utilizzato con:

  • (+) : Int * Int -> Int su Int
  • (+) : String * String -> String su String
+1

+1 grande risposta. Se anche [questo articolo di Liam MCLennnan copre un terreno simile] (http://withouttheloop.com/articles/2014-10-21-fsharp-adhoc-polymorphism/) –

2

Hai per dichiarare il vostro metodo che utilizza inline parola chiave per farlo funzionare:

let inline my_func (x,y) = x + y 

Per saperne di più su MSDN: Inline Functions (F#)

Problemi correlati