2014-04-16 11 views
5

Se faccio let f1 x = x; x+1, compilatore si lamenta: Warning 10: this expression should have type unit.Perché il compilatore smette di lamentarsi di "tipo unità" in questo caso?

Se lo faccio let f2 f = f(); 5, compilatore darà val f2 : (unit -> 'a) -> int = <fun>.

Domande

  1. Il sistema di tipo ne deduce che f è una funzione che prende unit come parametro e restituisce 'a. Ma se restituisce 'a, perché il compilatore non fornisce Warning 10?
  2. Se il compilatore non fornisce Warning 10, significa che pensa f() restituisce unit, non è vero? Allora perché dà 'a come tipo di ritorno?

risposta

6

Se il compilatore non fornisce Avviso 10, significa che pensa f() restituisce unità, non è vero?

Ovviamente, se il compilatore dà f2 il tipo (unit -> 'a) -> int, che significa che pensa f rendimenti 'a.

Cosa farebbe nel posto del compilatore?

  • Vuoi avvertire che f2 può essere applicato ad alcune funzioni che restituiscono i risultati non-unità, anche se può in realtà mai essere applicato in tal modo?

  • Vuoi dare f2 il tipo (unit -> unit) -> int e renderlo meno utile, costringendolo a essere utilizzato solo con funzioni che restituiscono ()?

  • Vuoi inventare un complicato sistema di avvertimenti rinviate dove f2 è di tipo (unit -> 'a) -> int ma produce un ulteriore avviso al momento della compilazione se viene applicato ad una funzione che non restituisce ()? Faresti funzionare questo sistema su tutti i moduli (gli avvertimenti posticipati di una funzione dovrebbero far parte delle firme del modulo)?

Gli avvisi sono solo suggerimenti utili, non garanzie. In caso di dubbio, non emettere l'avviso è la solita soluzione (e quasi tutti i compilatori adottano questa soluzione, non solo i compilatori OCaml).

+0

'se il compilatore dà f2 tipo (unit -> 'a) -> int, significa che pensa f2 restituisce' a' perché? 'f2' sicuramente è considerato per restituire' int', non è vero? –

+0

@JacksonTale Quello era un errore di battitura, intendevo "... che' f' return ''a'" –

+0

ahh, ok, che può spiegare –

3

Lasciatemi aggiungere un po 'alla risposta di Pascal.

Prova

let f1' (y : 'a)  x = y; x+1 
let f1'' (y : 'a list) x = y; x+1 

let f2' (f : unit -> 'a)  = f(); 5 
let f2'' (f : unit -> 'a list) = f(); 5 

f1' e f2' ti danno nessun avvertimento ma f1'' e f2'' fare.

Perché solo per f1'' e f2''?Dal momento che il correttore di tipo OCaml sicuramente sa che i tipi di e1 in e1 ; e2 non sono unit (sono 'a list).

Per f1' e f2', il tipo di e1 è una variabile di tipo 'a. Possono essere istanziati a unit a seconda di come vengono utilizzati f1' e f2', quindi è possibile che possano essere utilizzati "correttamente". Pensando a questa possibilità, il compilatore non li avvisa.

Personalmente preferisco forzare semplicemente il tipo di tipo e1 in e1 ; e2unit. Ma OCaml è più rilassato qui.

+0

'' a' include' unità'? –

+0

@JacksonTale Sì, ''a' può essere istanziato in qualsiasi tipo incluso' unità', altrimenti sarebbe impossibile applicare l'identità (di tipo' 'a ->' a' a '()'. Ma questo è molto utile (e quindi possibile): 'Sia id x = x in id()' –

+0

@PascalCuoq ah, ok, pensavo che il tipo 'unit' sia speciale e complementare al tipo '' a' –

5

Penso che questo sia un comportamento legacy dal compilatore. Utilizzare -strict-sequence per risolvere il problema:

$ ocaml 
# let f2 f = f(); 5;; 
val f2 : (unit -> 'a) -> int = <fun> 

Ma:

$ ocaml -strict-sequence 
# let f2 f = f(); 5;; 
val f2 : (unit -> unit) -> int = <fun> 

Se si utilizza ocamlbuild, si dovrebbe mettere questo nel vostro _tags del file:

true: strict_sequence 
Problemi correlati