[英]difference between variable definition in a Haskell source file and in GHCi?
在Haskell源文件中,我可以編寫
a = 1
而我的印象是,我必須在GHCi中編寫與
let a = 1
,為a = 1
在GHCI給出了一個解析錯誤=
。
現在,如果我寫
a = 1
a = 2
在源文件中,我將獲得有關的多個聲明錯誤a
,但它是確定在GHCI寫:
let a = 1
let a = 2
有人可以幫助您闡明兩種樣式之間的區別嗎?
交互式解釋器中的連續let
“語句”實際上等同於嵌套的let
表達式。 它們的行為就好像在隱式in
執行了該分配,並且其余的解釋器會話包括let
的主體。 那是
>>> let a = 1
>>> let a = 1
>>> print a
是相同的
let a = 1 in
let a = 1 in
print a
Haskell有一個主要區別,即具有相同名稱和相同作用域的兩個定義,以及在嵌套作用域中具有相同名稱的兩個定義。 文件中的GHCi vs模塊與此處的基本概念並沒有真正的聯系,但是如果您不熟悉這些情況,確實會導致遇到問題。
let表達式(以及do塊中的let語句)創建具有相同作用域的一組綁定,而不僅僅是單個綁定。 例如,作為一個表達式:
let a = True
a = False
in a
或使用花括號和分號(無需打開多行模式即可更方便地粘貼到GHCi中):
let { a = True; a = False} in a
無論在模塊中還是在GHCi中,這都將失敗。 不能有一個同時為True
和False
變量a
,並且不能在同一范圍內有兩個名為a
獨立變量(否則就不可能知道源文本a
指的是哪個變量)。
單個綁定集中的變量都“一次”定義; 他們寫的順序根本不相關。 您會看到這一點,因為可以定義互相引用的相互遞歸綁定,並且不可能一次以任何順序定義一次:
λ let a = True : b
| b = False : a
| in take 10 a
[True,False,True,False,True,False,True,False,True,False]
it :: [Bool]
在這里,我定義了一個交替的True
和False
的無限列表,並使用它來得出有限的結果。
Haskell模塊是單個作用域,包含文件中的所有定義。 就像在具有多個綁定的let表達式中一樣,所有定義都“立即發生” 1 ; 它們只是按特定順序排列,因為將它們寫下來不可避免地會引入一個順序。 所以在一個模塊中:
a = True
a = False
如您所見,給您一個錯誤。
在do-block中,您具有let語句而不是let表達式。 2,這些沒有一個in
,因為他們只是在做塊的整個其余部分的范圍。 3 GHCi命令非常類似於在IO
do-block中輸入語句,因此您在此處具有相同的選項,這就是您在示例中使用的選項。
但是,您的示例包含兩個 let綁定,而不是一個。 因此,在兩個單獨的范圍中定義了兩個單獨的變量a
。
哈斯克爾不關心(幾乎從不)關於不同定義的書面命令,但它確實關心嵌套范圍的“嵌套順序”; 規則是,當您引用變量a
,您將獲得a
的最內層定義,其范圍包含該引用。 4
順便說一句,通過在內部作用域中重用名稱來隱藏外部作用域的名稱稱為陰影 (我們稱內部定義陰影外部作用域)。 這是一個有用的通用編程術語,因為該概念以多種語言出現。
因此,GHCi與模塊中關於何時可以兩次定義名稱的規則並不是不同的,只是不同的上下文使不同的事情變得容易。
如果要在模塊中放置一堆定義,那么容易做的就是將它們全部都設為頂級定義,它們都具有相同的作用域(整個模塊),因此,如果使用相同的名稱,則會出現錯誤兩次。 您需要做更多的工作才能嵌套定義。
在GHCi中,您一次輸入一個命令,使用多行命令或大括號和分號樣式會更麻煩,因此,要輸入多個定義,最簡單的方法就是使用多個let語句,因此如果重用名稱,最終會掩蓋早期的定義。 5您必須更加故意地嘗試在同一范圍內實際輸入多個名稱。
1或更准確地說,綁定“就是”,根本沒有任何“綁定發生的時間”的概念。
2或者更確切地說:您擁有let語句和let表達式,因為語句主要由表達式組成,而let表達式始終可作為表達式有效。
3您可以看到這是一條一般規則,即do-block中的后續語句在概念上嵌套在所有較早的語句中,因為這就是將它們轉換為monadic操作時的含義。 確實讓語句實際上是翻譯,讓表達式用做塊內的其余部分in
的一部分。
4它不是模棱兩可的,就像在相同范圍內具有相同名稱的兩個變量一樣,盡管不可能引用任何進一步的定義。
5並請注意,您之前定義的任何在引用陰影之前引用該名稱的內容仍會像以前引用該名稱一樣完全一樣。 這包括返回變量值的函數。 這是最容易理解的陰影作為引入,恰好具有相同的名稱作為較早的一個不同的變量,而不是試圖為真正了解它改變了什么早前變量名指。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.