2016-06-26 44 views
7

Haskell'deki değişmez değişkenler kavramıyla oldukça kafam karıştı. Haskell'deki değişkenlerin değerini değiştiremeyiz gibi görünüyor.Haskell'de değişmez değişken ne anlama geliyor?

Prelude> foo x=x+1 
Prelude> a=1 
Prelude> a 
1 
Prelude> foo a 
2 
Prelude> a=2 
Prelude> a 
2 
Prelude> foo a 
3 

değişmez değişkenlerin fikri ile bu çatışmayı mı: Ben GHCi kodu aşağıdaki çalıştı zaman değişkenlerin değeri değiştirmek yaptığı gibi Ama görünüyordu?

Çok teşekkürler!

+1

bu ripimde çalışmıyor ... – Netwave

+0

'a = 1; a = 2' bir '.hs' dosyası içinde ve ghc ile derler ... – Bakuriu

+8

GHCi komutları IO eylemleridir, bu yüzden yazdığınız her şey bir' do' bloğu içinde olsaydı. Bunun anlamı, aynı adaya sonraki atamanın iç içe geçmiş gibi olduğunu, yani eski ciltlemenin * gölgelendiğini gösterir. – Bakuriu

cevap

18

Haskell, varolan değişkenleri değiştirmenize izin vermez. Ancak, değişken adlarını yeniden kullanmanıza izin veriyor ve burada olan tüm bunlar. Bu görmenin yollarından biri değişken ilan edildi :i[nfo] yönergesi kullanıldığında, GHCi sormaktır:

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 

Bunlar aslında sadece aynı adı çağrılacak gerçekleşmesi iki tamamı ayrı, farklı değişkenler vardır! , Sadece a için sorarsanız, yeni tanım olacaktır “ ” tercih edilir, ancak yorumlarda chi tarafından belirttiği gibi eski bir, hala orada bunu görmek – bir yoludur bir işlevde a kullanmaktır:

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 asla ayrıca a denir yeni bir değişken tanımladığınız bakım gerekir; Bakış açısına göre a, her zaman olduğu gibi duran değişmez bir değişkendi.


GHCi'nin neden daha sonra tanımlamayı tercih ettiği hakkında biraz konuşmaya değer. Bu değil, aksi takdirde Haskell kodunda gerçekleşir;

a = 1 
a = 2 

main :: IO() 
main = print a 

böyle bir şey GHCi izin verilir sağlamasının nedeni Haskell modüllerinden farklı çalışmasıdır: Aşağıdaki modülünü derlemeye çalışırsanız, özellikle basitçe bir hata ile ilgili yinelenen tanımını verir. GHCi komutlarının dizisi, aslında IO monad& hançerdeki eylemlerinin bir dizisini oluşturur;; yani program monads hakkında öğrendiğim eğer bu

main = 
    let a = 1 in (let a = 2 in (print a)) 

için sadece sözdizimsel şeker olduğunu bileceksiniz ve bu gerçekten neden için çok önemli bit, Şimdi

main :: IO() 
main = do 
    let a = 1 
    let a = 2 
    print a 

olması gerekir a adını yeniden kullanabilirsiniz: ikincisi, a = 2,'u daha dar bir kapsamda yaşar. Yani daha yerel ve yerel tanımların önceliği var.Bunun iyi bir fikir olup olmadığı biraz tartışmalıdır; bunun için iyi bir argüman Eğer

greet :: String -> IO() 
greet name = putStrLn $ "Hello, "++name++"!" 

gibi bir işlevi olabilir ve biri başka bir yerde yanında

name :: Car -> String 
name car | rollsOverAtRightTurn car = "Reliant Robin" 
     | fuelConsumption car > 50*litrePer100km 
             = "Hummer" 
     | ...      = ... 

tanımlar sırf bu çalışma durmayacak yani, gerçekten çok kullanışlı Eğer “ yeniden tanımlayabilirsiniz o ” değişkenleri, GHCi'de dalga geçerken, gibi bir şeyleri uygun bir programda yeniden tanımlamak için iyi bir fikir olsa da, tutarlı davranış göstermesi beklenir.


& dagger; Dfeuer sözleri gibi, bu tüm gerçek değildir. GHCi'de IO blokajında ​​izin verilmeyen bazı şeyler yapabilirsiniz, özellikle data türlerini ve class es özelliklerini tanımlayabilirsiniz. Fakat herhangi bir normal ifade veya değişken tanım, IO monad'ında olduğu gibi davranır. Eğer Aslında görebileceğiniz gibi

+0

Eksik olan bir şey: GHCi, Haskell 'in' sözdiziminde izin verilmeyen 'data',' newtype', 'type',' class' ve 'instance' bildirimlerine izin verir. – dfeuer

+1

GHCi'nin * etkileşimli * bir ortam olduğu göz önünde bulundurulduğunda, bu önemli bir özelliktir. Bir tanımı yanlış yazmanın kaç kez oldu? Eğer bunu yaptığınız her seferinde tamamen yeni bir isim seçmeniz gerekiyorsa, “myFunction7” gibi tüm okunabilir isimlerle “myFunction” fonksiyonunun bir hata içerdiği ve “her zaman” kelimesini eklediğimi hatırlamanız gerekiyor. Doğru tanımı kullanarak ... – Bakuriu

+0

Sağ. Eğer gerekliyse, farklı bir iş akışına, muhtemelen açık bir kapsamda olan bir şeye adapte olmalıyız. – leftaroundabout

0

(GHCi kullanan diğer cevabı ... iyi ama o GHCi veya monads özgü değildir netleştirmek için) o aşağıdaki Haskell programı

main = 
    let x = 1 in 
    let f y = x + y in 
    let x = 2 in 
    print (x * f 3) 

, 10 yerine 8 yazdırır, değişkenler yalnızca Haskell'de "mutasyona uğramış" değil "bağlı" olabilir. Diğer bir deyişle, yukarıdaki programı eşdeğerdir (denilen α eşdeğer tek bağlı değişken isimleri tutarlı değişikliği anlamına; daha ayrıntılı bilgi için https://wiki.haskell.org/Alpha_conversion bakınız) bu açık

main = 
    let x1 = 1 in 
    let f y = x1 + y in 
    let x2 = 2 in 
    print (x2 + f 3) 

bu x1 ve x2 farklı değişkenlerdir.