Bir fonksiyona atıfta bulunulan referans şeffaflığı, bu fonksiyonu uygulamanın sonucunu sadece argümanlarının değerlerine bakarak belirleyebileceğinizi belirtir. Referans olarak saydam işlevleri herhangi bir programlama dilinde yazabilirsiniz, örneğin Python, Scheme, Pascal, C
Öte yandan, çoğu dilde referans olarak saydam olmayan işlevler de yazabilirsiniz. Örneğin, bu Python işlevi:
counter = 0
def foo(x):
global counter
counter += 1
return x + counter
aslında referans olarak saydam değildir, aslında
foo(x) + foo(x)
ve
2 * foo(x)
Herhangi bir argüman için farklı değerler üretecektir x
. Bunun nedeni, işlevin global bir değişkeni kullanması ve değiştirmesidir, bu nedenle her çağrının sonucu, yalnızca işlevin argümanına değil, bu değişen duruma bağlıdır.
Tamamen işlevsel bir dil olan Haskell, saf işlevlerin uygulandığı ve her zaman referans olarak şeffaf olan ifade değerlendirmesini kesin olarak ayırır , eylem yürütmesinden (özel değerlerin işlenmesi), referans olarak saydam olmayan, yani aynı işlemi yürütmek her seferinde bir farklı sonuç
Yani, herhangi bir Haskell işlevi için
f :: Int -> Int
ve herhangi bir tamsayı x
, her zaman doğrudur
2 * (f x) == (f x) + (f x)
Bir eylem örneği, kütüphane işlevinin sonucudur getLine
:
getLine :: IO String
İfade değerlendirmesi sonucunda, bu işlev (aslında bir sabit) her şeyden önce saf türde bir değer üretir IO String
. Bu türdeki değerler, diğerleri gibi değerlerdir: bunları etrafa aktarabilir, veri yapılarına koyabilir, özel fonksiyonlar kullanarak oluşturabilir ve benzeri işlemleri yapabilirsiniz. Örneğin, bunun gibi eylemlerin bir listesini yapabilirsiniz:
[getLine, getLine] :: [IO String]
Eylemler, Haskell çalışma zamanına bunları yazarak yürütmelerini söyleyebilmeniz için özeldir:
main = <some action>
Bu durumda, Haskell programınız başlatıldığında, çalışma zamanı muhtemelen yan etkiler oluşturarak, ona bağlı eylemi yürütürmain
ve yürütür . Bu nedenle, eylem yürütme başvuru açısından saydam değildir, çünkü aynı eylemi iki kez yürütmek, çalışma zamanının girdi olarak aldığı duruma bağlı olarak farklı sonuçlar üretebilir.
Haskell'in tip sistemi sayesinde, hiçbir zaman başka bir tipin beklendiği bir bağlamda asla kullanılamaz ve bunun tersi de geçerlidir. Bu nedenle, bir dize uzunluğunu bulmak istiyorsanız, length
işlevi kullanabilirsiniz :
length "Hello"
5 döndürür. Ancak terminalden okunan bir dizgenin uzunluğunu bulmak istiyorsanız, yazamazsınız.
length (getLine)
çünkü bir tür hatası alıyorsunuz: length
bir tür listesinin girişini bekliyor (ve bir Dize, aslında bir listedir) ancak getLine
türün bir değeridir IO String
(bir eylem). Bu şekilde, tip sistemi getLine
(yürütülmesi çekirdek dilin dışında gerçekleştirilir ve referans olarak saydam olmayan) bir işlem değerinin, işlem dışı bir değerin içine gizlenememesini sağlar Int
.
DÜZENLE
Exizt sorusuna cevap vermek için, işte konsoldan bir satır okuyan ve uzunluğunu basan küçük bir Haskell programı.
main :: IO () -- The main program is an action of type IO ()
main = do
line <- getLine
putStrLn (show (length line))
Ana eylem, sırayla yürütülen iki alt bölümden oluşur:
getline
Çeşidi IO String
,
- ikinci bir fonksiyonu değerlendirilerek oluşturulur
putStrLn
Çeşidi String -> IO ()
argüman ile.
Daha doğrusu, ikinci eylem inşa
line
ilk eylem tarafından okunan değere bağlanma ,
- saf fonksiyonların değerlendirilmesi
length
(tamsayı olarak uzunluk hesaplamak) ve sonra show
(tamsayıyı bir dizgeye çevirmek),
- eylemini
putStrLn
sonucuna fonksiyon uygulayarak oluşturmak show
.
Bu noktada, ikinci eylem gerçekleştirilebilir. "Merhaba" yazdıysanız, "5" yazacaktır.
Notu kullanarak bir işlemden bir değer elde <-
ederseniz, bu değeri yalnızca başka bir işlem içinde kullanabileceğinizi unutmayın, örneğin:
main = do
line <- getLine
show (length line) -- Error:
-- Expected type: IO ()
-- Actual type: String
çünkü show (length line)
tipe String
sahipken, gösterimde bir eylemin ( getLine
türden IO String
) başka bir eylemin (örneğin putStrLn (show (length line))
türden IO ()
) takip edilmesini gerektirdiği halde vardır .
EDIT 2
Jörg W Mittag'ın referandum şeffaflığı tanımı benimkinden daha genel (onun cevabını aştım). Kısıtlı bir tanım kullandım çünkü sorudaki örnek fonksiyonların geri dönüş değerine odaklandı ve bu yönü açıklamak istedim. Bununla birlikte, genel olarak RT, bir ifadenin değerlendirilmesinden kaynaklanan küresel duruma yapılan değişiklikler ve çevre ile etkileşimler (IO) de dahil olmak üzere tüm programın anlamını ifade eder. Bu nedenle, doğru, genel bir tanım için, bu cevaba başvurmalısınız.