Haskell non consente di modificare variabili esistenti. Tuttavia, ti consente di riutilizzare i nomi delle variabili, , e questo è tutto ciò che sta accadendo qui. Un modo di vedere questo è quello di chiedere GHCi, usando la direttiva :i[nfo]
, in cui è stata dichiarata la variabile:
Prelude> let a = 1
Prelude> :i a
a :: Num a => a -- Defined at <interactive>:2:5
Prelude> let a = 2
Prelude> :i a
a :: Num a => a -- Defined at <interactive>:4:5
Questi sono in realtà due intero separato, diverse variabili, che ha appena capita di essere chiamato con lo stesso nome! Se basta chiedere per a
, la definizione più recente sarà “ preferito ”, ma quello vecchio è ancora lì – un modo di vedere questo, come notato da chi nei commenti, è quello di utilizzare a
in una funzione:
Prelude> let a = 2
Prelude> :i a
a :: Num a => a -- Defined at <interactive>:4:5
Prelude> let f x = a + x
Prelude> let a = 3
Prelude> f (-2)
0
f
non deve mai preoccuparsi di aver definito una nuova variabile chiamata anche a
; dal suo punto di vista a
era una variabile immutabile che rimane sempre così com'è.
Vale la pena parlare del motivo per cui GHCi preferisce la definizione successiva. Questo è non altrimenti si verifica nel codice Haskell; in particolare se si tenta di compilare il seguente modulo, dà semplicemente un errore riguardante definizione duplicata:
a = 1
a = 2
main :: IO()
main = print a
La ragione per cui qualcosa di simile è consentito in GHCi è che funziona diverso dai moduli Haskell. La sequenza di comandi GHCi forma infatti una sequenza di azioni nella monade IO& dagger;; vale a dire il programma avrebbe dovuto essere
main :: IO()
main = do
let a = 1
let a = 2
print a
Ora, se hai imparato a conoscere monadi saprete che questo è lo zucchero sintattico per
main =
let a = 1 in (let a = 2 in (print a))
e questo è davvero il bit cruciale per il motivo è possibile riutilizzare il nome a
: il secondo, a = 2
, vive in un ambito più stretto rispetto al primo. Quindi è più locale e le definizioni locali hanno la priorità.Se questa è una buona idea è un po 'discutibile; un buon argomento per esso è che si può avere una funzione come
greet :: String -> IO()
greet name = putStrLn $ "Hello, "++name++"!"
e non sarà smettere di lavorare solo perché qualcuno definisce altrove
name :: Car -> String
name car | rollsOverAtRightTurn car = "Reliant Robin"
| fuelConsumption car > 50*litrePer100km
= "Hummer"
| ... = ...
Inoltre, è davvero molto utile che si può “ redefine ” variabili mentre si scherza in GHCi, anche se è non una così buona idea per ridefinire le cose in un programma corretto, che dovrebbe mostrare un comportamento coerente.
e pugnale; Come osserva Dfeuer, questa non è tutta la verità. È possibile eseguire alcune operazioni in GHCi che non sono consentite in un blocco di IO
, in particolare è possibile definire i tipi data
e class
es. Ma qualsiasi affermazione normale o definizione di variabile si comporta come nella monade IO
.
che non funziona nel mio modo ... – Netwave
Prova a mettere 'a = 1; a = 2' all'interno di un file '.hs' e compilarlo con' ghc' ... – Bakuriu
I comandi GHCi sono azioni IO, quindi è come se tutto ciò che si digita fosse all'interno di un blocco 'do'. Il che significa che il successivo incarico con lo stesso nome è come nidificato 'let's, tu * shadow * il vecchio bind. – Bakuriu