2015-10-08 7 views
35

Se dico let 5 = 10, perché 5 + 1 restituisce 6 anziché 11?Informazioni su "let 5 = 10`

+19

Una risposta immediata sarebbe "perché non si può ridefinire ciò che' 5' è". Tuttavia, in realtà sono abbastanza sorpreso scrivendo che "Let 5 = 10' sia persino possibile! – duplode

+3

quello che puoi fare è 'overload' il' + ':' let 1 + 1 = 3 in 1 + 1';) – Carsten

+8

btw: Penso che il '5' in' let 5 = 10' sia ancora un pattern (solo uno che non è mai abbinato) quindi non legherà nulla (come in 'let (x, 5) = (6,6)') – Carsten

risposta

52

Quando si dice

let 5 = 10 

non è una ridefinizione del 5, è un pattern matching, la stessa che si verifica quando si dice

foo 5 = undefined 
... foo 10 ... 

Il modello non è sufficiente se è sempre abbinato.

Nelle let-espressioni la corrispondenza è pigra. Ciò significa che la corrispondenza viene eseguita solo quando viene valutata una variabile vincolata da essa. Questo ci permette di scrivere cose come

let foo = undefined in 10 

Nella tua espressione, nessuna variabile è vincolata, quindi il modello non è mai abbinato.

Probabilmente tali modelli senza variabili non hanno senso nei legami e dovrebbero essere rilevati dal compilatore, ma il linguaggio non li vieta.

+5

Rassicurato 'let (5, x) = (10, True) in x' consegna' *** Eccezione: : 2: 5-21: Pattern irreversibile fallito per pattern (5, x) '. – pigworker

+3

Questo è sciocco per legami letali, ma non per tutti: ad es. 'only5 xs = [5 | 5 <- xs] 'ha senso (se stai bene con liste' fail'). – user3237465

+0

@ user3237465 sì, intendevo solo let-binding. In aggiornamento. –

15

Fondamentalmente,

let 5 = 10 in ... 

è equivalente a

case 10 of ~5 -> ... 

nota la ~, che segna un pigro, o irrefutabile modello. Questo è un modello che corrisponde a tutto e che rimanda la corrispondenza al punto in cui è effettivamente richiesta una variabile. Non ci sono variabili nel modello 5, quindi non succede mai niente.

Questo caso d'angolo è abbastanza inutile, e probabilmente il compilatore dovrebbe emettere un avvertimento qui.

Per chiarire il significato di modelli pigri, considerare questo:

case f 3 of 
    (x,y) -> g 10 x y 

qui f 3 viene valutata per prima (a WHNF), esponendo il costruttore coppia. Quindi x,y sono associati ai componenti della coppia (non ancora valutata). Infine, viene calcolato g 10, il risultato viene applicato a x (che potrebbe essere richiesto ora), quindi a (che potrebbe richiedere x o).

In confronto,

case f 3 of 
    ~(x,y) -> g 10 x y 

non inizia a valutare f 3. Invece x è legato al valore non valorizzato fst (f 3) e è legato al valore non valutato snd (f 3). Iniziamo invece con la valutazione di g 10. Quindi, lo applichiamo a x: ciò potrebbe causare la richiesta di x, innescando la valutazione di f 3. Quindi, applichiamo il risultato a , causando una valutazione simile.La maggior parte dell'implementazione sarà in realtà condivide il risultato di f 3 tra x e in modo che venga calcolato al massimo una volta.

1

Come @ n. sta dicendo, tu sei il modello di corrispondenza. Ecco alcuni esempi.

modello corrisponde può avere successo

Prelude> let (a, 10) = (15, 10) in a 
15 

o fallire.

Prelude> let (a, 10) = (15, 15) in a 
*** Exception: <interactive>:5:5-22: Irrefutable pattern failed for pattern (a, 10) 

Poiché Haskell è pigro, il codice verrà eseguito correttamente se non si utilizza il valore risultante. Questo è in sostanza quello che stai facendo:

Prelude> let (a, 10) = (15, 15) in "Something else" 
"Something else" 

Nota che i tipi devono ancora verificare:

Prelude> let (a, 10, 999) = (15, 15) in "Something else" 

<interactive>:7:20: error: 
    • Couldn't match expected type ‘(t, Integer, Integer)’ 
        with actual type ‘(Integer, Integer)’ 
    • In the expression: (15, 15) 
     In a pattern binding: (a, 10, 999) = (15, 15) 
     In the expression: let (a, 10, 999) = (15, 15) in "Something else" 
    • Relevant bindings include a :: t (bound at <interactive>:7:6) 
+0

" Poiché Haskell è pigro, il tuo codice andrà a buon fine se non usi il valore risultante "- Vale la pena ricordare che importa anche che' let' le associazioni corrispondono pigramente per impostazione predefinita. 'case (15, 15) di {(a, 10) ->" Qualcos'altro "}' si blocca, mentre 'case (15, 15) di {~ (a, 10) ->" Qualcos'altro "}' (che , grazie alla corrispondenza pigra, [equivale al tuo terzo esempio] (https://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-440003.12)) ha successo. – duplode

+0

@duplode, penso che lazy default in 'let' e' where' sia stata una cattiva idea, ed è la ragione per cui i pattern bang possono essere confusi a volte. – dfeuer

+0

@dfeuer Che dire del binding a una lista infinita? Per esempio 'let nats = [1 ..] in takeWhile isOkay nats' – Teodor