2012-11-24 19 views
6

yılında 'izin' kullanarak. Ben sorun let -statements saflığı ihlal etmeyen anlayış neden yaşıyorum. Örneğin (GHCi olarak)Fonksiyonel Saflık ben Haskell öğrenme üzerinde çalışıyorum, ben o tamamen işlevsel bir dildir anlıyorum Haskell

:

Prelude> let e = exp 1 
Prelude> e 
2.718281828459045 
Prelude> let e = 2 
Prelude> e 
2 

bir yan etkisi üreten ikinci let ifadesi değil mi? Yoksa ikinci let ifadesi yeni bir kapanış mı? Sizin ikinci let

+0

@jberryman 2) ve 3) [yanıtım] 'ın ikinci yarısında zaten kapandı (http://stackoverflow.com/questions/13545580/functional-purity-using-let-in-haskell/13545731#13545731 dbaupp'ın aşağıdaki benzer yorumu izleyerek. – AndrewC

cevap

21

mevcut değişkeni gölgeler e için yeni bir bağlama oluşturur. e'u değiştirmez. Kolayca aşağıdaki ile kontrol edebilirsiniz:

*Main> (let length = 2 in show length) ++ ' ':show (length "Hello") 
"2 5" 

:

Prelude> let e = 1 
Prelude> let f() = "e is now " ++ show e 
Prelude> f() 
"e is now 1" 
Prelude> let e = 2 
Prelude> e 
2 
Prelude> f() 
"e is now 1" 
Prelude> 
16

let tek değiştirilemez değere sahip yeni bir yerel değişken tanıtır ve herhangi çevreleyen tanımların daha fazla yerel kapsamı vardır örneğin bu yüzden İşte ilk length 2 değerine sahiptir ancak parantez onun kapsamı yerel. Parantezlerin dışında, length, her zaman ne anlama geldiğini gösterir. Hiçbir şey düzenlenmemiş, sadece farklı bir kapsamda başka biriyle aynı adı taşıyan daha yerel bir değişken tanıtılmıştır. en parantez ihmal ve length bir sayı ve bir işlev yapmaya yaparak GHCi deli yapalım:

*Main> let length = 2 in show length ++ ' ':show (length "Hello") 

<interactive>:1:14: 
    No instance for (Num ([Char] -> a0)) 
     arising from the literal `2' 
    Possible fix: add an instance declaration for (Num ([Char] -> a0)) 
    In the expression: 2 
    In an equation for `length': length = 2 
    In the expression: 
     let length = 2 in show length ++ ' ' : show (length "Hello") 

<interactive>:1:19: 
    No instance for (Show ([Char] -> a0)) 

     arising from a use of `show' 
    Possible fix: add an instance declaration for (Show ([Char] -> a0)) 
    In the first argument of `(++)', namely `show length' 
    In the expression: show length ++ ' ' : show (length "Hello") 
    In the expression: 
     let length = 2 in show length ++ ' ' : show (length "Hello") 

Ve burada örnek:

*Main> let e = exp 1 in show e ++ " " ++ let e = 2 in show e 
"2.718281828459045 2" 
Ben kapsamını vurgulamak parantez ekleyeceğiz

:

*Main> let e = exp 1 in (show e ++ " " ++ (let e = 2 in (show e))) 
"2.718281828459045 2" 

ilk e

gizli ziyade düzenlenir. Referans şeffaflık korunur, ancak bu kesinlikle kötü bir uygulamadır çünkü takip edilmesi zordur.

testdo = do 
    let e = exp 1 
    print e 
    let e = 2 
    print e 

Şimdi bu hırsızlık gibi bir sürü kötü görünüyor itiraf etmeliyim:


Şimdi gizlice interaktif istemi IO monad bir büyük do bloğu gibi biraz, o yüzden o bakmama izin vermek şeffaflık değinilerek, ama artık çok yaptığı gibi bu görünüyor akılda:

testWrite = do 
    writeFile "test.txt" "Hello Mum" 
    xs <- readFile "test.txt" 
    print xs 
    writeFile "test.txt" "Yo all" 
    xs <- readFile "test.txt" 
    print xs 

Şimdi referans şeffaflık var, ne anlamda? xs açıkça iki farklı dizeye karşılık gelir. Peki, bu do notasyonu aslında ne anlama geliyor? Bu Şimdi

testWrite = writeFile "test.txt" "Hello Mum" 
     >> readFile "test.txt" 
     >>= (\xs -> print xs 
     >> writeFile "test.txt" "Yo all" 
     >> readFile "test.txt" 
     >>= (\xs -> print xs)) 

ne atama benziyor sadece yerel kapsamı yeniden olduğunu daha açık için sözdizimsel şeker var. Sen muhtemelen aynı şeyi yapıyor

increment :: [Int] -> [Int] 
increment = \x -> map (\x -> x+1) x 

yapmak mutluyuz.atama olduğu ortaya çıktı Ne


Özeti
yeni bir yerel kapsamı sadece giriştir. Uf. Bunu çok kullanırsanız, kodunuzun ne anlama geldiğini çok net bir şekilde ifade edemezsiniz.

+6

Sorunun bir do-notasyon bağlamında 'let' kullanacağını unutmayın, yani 'do {...; e = 1 olsun; ...} 'yerine' izin ver… 'bağlamında. Muhakeme hemen hemen aynıdır, ama söz etmeye değer. – huon

+0

@dbaupp İyi nokta. Söz. Teşekkürler. – AndrewC