2009-07-15 10 views
18

Non capisco come funzioni la restrizione del valore in F #. Ho letto la spiegazione nello wiki e nello MSDN documentation. Quello che non capisco è:Informazioni sugli errori di restrizione del valore F #

  1. Perché, ad esempio, questo mi dà un errore di valore di restrizione (Tratto da this domanda):

    let toleq (e:float<_>) a b = (abs (a - b)) < e 
    

    Ma THS non lo fa:

    let toleq e (a:float<_>) b = (abs (a - b)) < e 
    
  2. Questo è generalizzata tutto bene ...

    let is_bigger a b = a < b 
    

    ma questo non è (si precisa come int):

    let add a b = a + b 
    
  3. Perché funzioni con parametri impliciti generare valore Limitazione:

    questo:

    let item_count = List.fold (fun acc _ -> 1 + acc) 0 
    

    vs questo:

    let item_count l = List.fold (fun acc _ -> 1 + acc) 0 l 
    

    (attenzione, se lo faccio utilizzare questa funzione in un frammento di codice l'errore VR sarà andato, ma poi la funzione sarà specificato il tipo ho usato per, e voglio che sia generalizzata)

Come funziona?

(sto usando l'ultima F #, v1.9.6.16)

+0

Croce rif ad un'altra domanda su stesso argomento: http://stackoverflow.com/questions/416508/f-compiler-error-fs0030-problems-with-the-value-restriction – Benjol

risposta

16

EDIT

Meglio/recente Info è qui: Keeping partially applied function generic

(originale sotto)

penso una cosa pragmatica qui non è cercare di capire questo troppo profondamente, ma piuttosto conoscere un paio di strategie generali per superare la VR e andare avanti con il tuo lavoro. È una risposta un po 'fuoriuscita, ma non sono sicuro che abbia senso dedicare del tempo a comprendere le intrecci del sistema di tipo F # (che continua a cambiare in modi minori da versione a versione) qui.

Le due strategie principali che vorrei sostenere sono queste. In primo luogo, se si sta definendo un valore con un tipo di funzione (tipo con una freccia '->'), quindi assicurarsi che sia una funzione sintattica facendo eta-conversion:

// function that looks like a value, problem 
let tupleList = List.map (fun x -> x,x) 
// make it a syntactic function by adding argument to both sides 
let tupleList l = List.map (fun x -> x,x) l 

In secondo luogo, se si incontrano ancora VR/generalizzando problemi, quindi specificare l'intero firma tipo di dire ciò che si vuole (e poi 'marcia indietro', come F # permette):

// below has a problem... 
let toleq (e:float<_>) a b = (abs (a - b)) < e 
// so be fully explicit, get it working... 
let toleq<[<Measure>]'u> (e:float<'u>) (a:float<'u>) (b:float<'u>) : bool = 
    (abs (a - b)) < e 
// then can experiment with removing annotations one-by-one... 
let toleq<[<Measure>]'u> e (a:float<'u>) b = (abs (a - b)) < e 

Penso che queste due strategie sono il miglior consiglio pragmatico. Detto questo, ecco il mio tentativo di rispondere alle tue domande specifiche.

  1. Non so.

  2. '>' è una funzione completamente generica ('a ->' a -> bool) che funziona per tutti i tipi, e quindi is_bigger generalizza. D'altra parte, '+' è una funzione 'in linea' che funziona su una manciata di tipi primitivi e una certa classe di altri tipi; può essere generalizzato solo all'interno di altre funzioni 'inline', altrimenti deve essere bloccato a un tipo specifico (o verrà impostato su 'int'). (Il metodo "in linea" del polimorfismo ad-hoc è il modo in cui gli operatori matematici in F # superano la mancanza di "classi di tipi".)

  3. Questo è il problema della "funzione sintattica" di cui sopra; 'compiliamo in campi/proprietà che, a differenza delle funzioni, non possono essere generici. Quindi, se vuoi che sia generico, rendilo una funzione. (Vedi anche this question per un'altra eccezione a questa regola.)

+2

Dmitri ha scritto un bel post su questo più recentemente: http://blogs.msdn.com/b/mulambda/archive/2010/05/01/value-restriction-in-f.aspx – Brian

2

Nessuno, comprese le persone in # team di F, conosce la risposta a questa domanda in modo significativo.

Il sistema di inferenza di tipo F # è esattamente come la grammatica VB6 nel senso che il compilatore definisce la verità.

Sfortunato, ma vero.

+1

Beh, scommetto che Don conosce la risposta. E F # è ancora in beta. Ad un certo punto dovremo rassodare le specifiche. E il compilatore non è una scatola nera; la fonte del compilatore F # è liberamente disponibile. Detto questo, non ti ho minimizzato, perché per la maggior parte non sono d'accordo (quasi nessuno lo sa, e la mancanza di una sintetica succinta è davvero sfortunata). – Brian

+0

Ogni lingua ha i suoi angoli e fessure. F # per la maggior parte è un linguaggio molto stabile, molto elegante e pratico (IMHO). Ovviamente, è ancora in corso, ma rispetto ad altri linguaggi in sviluppo (senza nomi di nomi) il futuro è sicuro per F #. Detto questo, non ti ho minimizzato neanche. –

+0

@Brian Don conosce la risposta solo perché ha accesso alla fonte. Non esiste una "teoria" di inferenza di tipo in F #. – user128807

4

La limitazione del valore è stata introdotta per risolvere alcuni problemi con il polimorfismo in presenza di effetti collaterali. F # eredita questo da OCaml, e credo che la restrizione del valore esista in tutte le varianti ML. Ecco uno morelinks da leggere, oltre ai link che hai citato. Poiché Haskell è puro, non è soggetto a questa restrizione.

Per quanto riguarda le vostre domande, penso che la domanda 3 sia veramente correlata alla restrizione del valore, mentre i primi due non lo sono.

+0

Sì. OCaml ha una restrizione del valore rilassata in cui consente variabili di tipo non generalizzate al livello più alto nel REPL dove vengono visualizzate come ''_a' piuttosto che'' a'.Quest'ultimo significa che il codice è polimorfico e funziona per tutti i tipi ''a' mentre il primo indica che il codice è monomorfico in questo tipo e funziona solo per un tipo specifico'' _a' e che non è stato ancora determinato. Ciò è reso più facile dal fatto che OCaml utilizza una rappresentazione uniforme dei dati per tutti i dati polimorfici. Sarebbe più difficile in F # perché i generici reificati hanno bisogno dell'esatto tipo monomorfico per essere conosciuti alla compilazione. –

Problemi correlati