在本書的前面一些章節(jié)里,我們有時候會以限制性的、簡單的形式來介紹一些概念。由于Haskell是一本比較深的語言,所以一次性介紹某個主題的所有特性會令人難以接受。當基礎鞏固后,我們就會進行更加深入的學習。
在Haskell語言的眾多實現(xiàn)中,有兩個被廣泛應用,Hugs和GHC。其中Hugs是一個解析器,主要用于教學。而GHC(GlasgowHaskellCompiler)更加注重實踐,它編譯成本地代碼,支持并行執(zhí)行,并帶有更好的性能分析工具和調試工具。由于這些因素,在本書中我們將采用GHC。
GHC主要有三個部分組成。
Note
我們如何稱呼GHC的各個組件
當我們討論整個GHC系統(tǒng)時,我們稱之為GHC。而如果要引用到某個特定的命令,我們會直接用其名字標識,比如ghc,ghci,runghc。
在本書中,我們假定你在使用最新版6.8.2版本的GHC,這個版本是2007年發(fā)布的。大多數(shù)例子不要額外的修改也能在老的版本上運行。然而,我們建議使用最新版本。如果你是Windows或者MacOSX操作系統(tǒng),你可以使用預編譯的安裝包快速上手。你可以從GHC下載頁面 找到合適的二進制包或者安裝包。
對于大多數(shù)的Linux版本,BSD提供版和其他Unix系列,你可以找到自定義的GHC二進制包。由于這些包要基于特性的環(huán)境編譯,所以安裝和使用顯得更加容易。你可以在GHC的二進制發(fā)布包頁面 找到相關下載。
我們在[附錄A]中提供了更多詳細的信息介紹如何在各個流行平臺上安裝GHC。
ghci程序是GHC的交互式解析器。它可以讓用戶輸入Haskell表達式并對其求值,瀏覽模塊以及調試代碼。如果你熟悉Python或是Ruby,那么ghci一定程度上和python,irb很像,這兩者分別是Python和Ruby的交互式解析器。
The ghci command has a narrow focus
We typically can not copy some code out of a haskell source file and paste it into ghci. This does not have a significant effect on debugging pieces of code, but it can initially be surprising if you are used to , say, the interactive Python interpreter.
在類Unix系統(tǒng)中,我們在shell視窗下運行ghci。而在Windows系統(tǒng)下,你可以通過開始菜單找到它。比如,如果你在WindowsXP下安裝了GHC,你應該從”所有程序”,然后”GHC”下找到ghci。(參考附錄A章節(jié)Windows 里的截圖。)
當我們運行ghci時,它會首先顯示一個初始banner,然后就顯示提示符Prelude>。下載例子展示的是Linux環(huán)境下的6.8.3版本。
$ ghci
GHCi, version 6.8.3: http://www.haskell.org/ghc/ :? for help
Loading package base ... linking ... done.
Prelude>
提示符Prelude標識一個很常用的庫Prelude已經(jīng)被加載并可以使用。同樣的,當加載了其他模塊或是源文件時,它們也會在出現(xiàn)在提示符的位子。
Tip
獲取幫助信息
在ghci提示符輸入 :?,則會顯示詳細的幫助信息。
模塊Prelude有時候被稱為“標準序幕”(the standardprelude),因為它的內容是基于Haskell 98標準定義的。通常簡稱它為“序幕”(theprelude)。
Note
關于ghci的提示符
提示符經(jīng)常是隨著模塊的加載而變化。因此經(jīng)常會變得很長以至在單行中沒有太多可視區(qū)域用來輸入。
為了簡單和一致起見,在本書中我們會用字符串 ‘ghci>' 來替代ghci的默認提示符。
你可以用ghci的 :setprompt 來進行修改。
Prelude> :set prompt "ghci>"
ghci>
prelude模塊中的類型,值和函數(shù)是默認直接可用的,在使用之前我們不需要額外的操作。然而如果需要其他模塊中的一些定義,則需要使用ghci的:module方法預先加載。
ghci> :module + Data.Ratio
現(xiàn)在我們就可以使用Data.Ratio模塊中的功能了。這個模塊提供了一些操作有理數(shù)的功能。
基本交互: 把ghci當作一個計算器 除了能提供測試代碼片段的交互功能外,ghci也可以被當作一個桌面計算器來使用。我們可以很容易的表示基本運算,同時隨著對Haskell了解的深入,也可以表示更加復雜的運算。即使是以如此簡單的方式來使用這個解析器,也可以幫助我們了解更多關于Haskell是如何工作的。 基本算術運算 我們可以馬上開始輸入一些表達式,看看ghci會怎么處理它們。基本的算術表達式類似于像C或是Python這樣的語言:用中綴表達式,即操作符在操作數(shù)之間。
ghci> 2 + 2
4
ghci> 31337 * 101
3165037
ghci> 7.0 / 2.0
3.5
用中綴表達式是為了書寫方便:我們同樣可以用前綴表達式,即操作符在操作數(shù)之前。在這種情況下,我們需要用括號將操作符括起來。
ghci> 2 + 2
4
ghci> (+) 2 2
4
上述的這些表達式暗示了一個概念,Haskell有整數(shù)和浮點數(shù)類型。整數(shù)的大小是隨意的。下面例子中的(^)表示了整數(shù)的乘方。
ghci> 313 ^ 15
27112218957718876716220410905036741257
在如何表示數(shù)字方面Haskell提供給我們一個特性:通常需要將負數(shù)寫在括號內。當我們要表示不是最簡單的表達式時,這個特性就開始發(fā)揮影響。
我們先開始表示簡單的負數(shù)
ghci> -3
-3
上述例子中的-是一元表達式。換句話說,我們并不是寫了一個數(shù)字“-3”;而是一個數(shù)字“3”,然后作用于操作符-。-是Haskell中唯一的一元操作符,而且我們也不能將它和中綴運算符一起使用。
ghci> 2 + -3
<interactive>:1:0:
precedence parsing error
cannot mix `(+)' [infixl 6] and prefix `-' [infixl 6] in the same infix expression
如果需要在一個中綴操作符附近使用一元操作符,則需要將一元操作符以及其操作數(shù)包含的括號內。
ghci> 2 + (-3)
-1
ghci> 3 + (-(13 * 37))
-478
如此可以避免解析的不確定性。當在Haskell應用(apply)一個函數(shù)時,我們先寫函數(shù)名,然后隨之其參數(shù),比如f3。如果我們不用括號括起一個負數(shù),就會有非常明顯的不同的方式理解f-3:它可以是“將函數(shù)f應用(apply)與數(shù)字-3”,或者是“把變量f減去3”。
大多數(shù)情況下,我們可以省略表達式中的空格(“空”字符比如空格或制表符tab),Haskell也同樣能正確的解析。但并不是所有的情況。
ghci> 2*3
6
下面的例子和上面有問題的負數(shù)的例子很像,然而它的錯誤信息并不一樣。
ghci> 2*-3
<interactive>:1:1: Not in scope: `*-'
這里Haskell把-理解成單個的操作符。Haskell允許用戶自定義新的操作符(這個主題我們隨后會講到),但是我們未曾定義過-。
ghci> 2*(-3)
-6
相比較其他的編程語言,這種對于負數(shù)不太一樣的行為可能會很些怪異,然后它是一種合理的折中方式。Haskell允許用戶在任何時候自定義新的操作符。這是一個并不深奧的語言特性,我們會在以后的章節(jié)中看到許多用戶定義的操作符。語言的設計者們?yōu)榱藫碛羞@個表達式強項而接受了這個有一點累贅的負數(shù)表達語法。
Haskell中表示布爾邏輯的值有這么兩個:True和False。名字中的大寫很重要。作用于布爾值得操作符類似于C語言的情況:(&&)表示“邏輯與”,(||)表示“邏輯或”。
ghci> True && False
False
ghci> False || True
True
有些編程語言中會定義數(shù)字0和False同義,但是在Haskell中并沒有這么定義,同樣的,也Haskell也沒有定義非0的值為True。
ghci> True && 1
<interactive>:1:8:
No instance for (Num Bool)
arising from the literal `1' at <interactive>:1:8
Possible fix: add an instance declaration for (Num Bool)
In the second argument of `(&&)', namely `1'
In the expression: True && 1
In the definition of `it': it = True && 1
我們再一次的遇到了很有前瞻性的錯誤。簡單來說,錯誤信息告訴我們布爾類型,Bool,不是數(shù)字類型,Num的一個成員。錯誤信息有些長,這是因為ghci會定位出錯的具體位置,并且給出了也許能解決問題的修改提示。 錯誤信息詳細分析如下。 “No instance for (Num Bool)” 告訴我們ghci嘗試解析數(shù)字1為Bool類型但是失敗。 “arising from the literal 1'” 表示是由于使用了數(shù)字1而引發(fā)了問題。 “In the definition of
it'” 引用了一個ghci的快捷方式。我們會在后面提到。
Tip 遇到錯誤信息不要膽怯 這里我們提到了很重要的一點,而且在本書的前面一些章節(jié)中我們會重復提到。如果你碰到一些你從來沒遇到過的問題和錯誤信息,別擔心(panic)。剛開始的時候,你所要的做的僅僅是找出足夠的信息來幫助解決問題。隨著你經(jīng)驗的積累,你會發(fā)現(xiàn)錯誤信息中的一部分其實很容易理解,并不會像剛開始時那么晦澀難懂。 各種錯誤信息都有一個目的:通過提前的一些調試,幫助我們在真正運行程序之前能書寫出正確的代碼。如果你曾使用過其它更加寬松(permissive)的語言,這種方式可能會有些震驚(shock).所以,拿出你的耐心來。 Haskell中大多數(shù)比較操作符和C語言以及受C語言影響的語言類似。
ghci> 1 == 1
True
ghci> 2 < 3
True
ghci> 4 >= 3.99
True
有一個操作符和C語言的相應的不一樣,“不等于”。C語言中是用!=表示的,而Haskell是用/=表示的,它看上去很像數(shù)學中的≠。
另外,類C的語言中通常用!表示邏輯非的操作,而Haskell中用函數(shù)not。
ghci> not True
False
類似于代數(shù)或是使用中綴操作符的編程語言,Haskell也有操作符優(yōu)先級的概念。我們可以使用括號將部分表達顯示的組合在一起,同時操作符優(yōu)先級允許省略掉一些括號。比如乘法比加法優(yōu)先級高,因此以下兩個表達式效果是一樣的。
ghci> 1 + (4 * 4)
17
ghci> 1 + 4 * 4
17
Haskell給每個操作符一個數(shù)值型的優(yōu)先級值,從1表示最低優(yōu)先級,到9表示最高優(yōu)先級。高優(yōu)先級的操作符先于低優(yōu)先級的操作符被應用(apply)。在ghci中我們可以用命令:info來查看某個操作符的優(yōu)先級。
ghci> :info (+)
class (Eq a, Show a) => Num a where
(+) :: a -> a -> a
...
-- Defined in GHC.Num
infixl 6 +
ghci> :info (*)
class (Eq a, Show a) => Num a where
...
(*) :: a -> a -> a
...
-- Defined in GHC.Num
infixl 7 *
這里我們需要找的信息是“infixl 6+”,表示(+)的優(yōu)先級是6。(其他信息我們稍后介紹。)“infixl 7”表示()的優(yōu)先級為7。由于()比(+)優(yōu)先級高,所以我們看到為什么1+44和1+(44)值相同而不是(1+4)4。
Haskell也定義了操作符的結合性(associativity)。它決定了當一個表達式中多次出現(xiàn)某個操作符時是否是從左到右求值。(+)和(*)都是左結合,在上述的ghci輸出結果中以infixl表示。一個右結合的操作符會以infixr表示。
ghci> :info (^)
(^) :: (Num a, Integral b) => a -> b -> a -- Defined in GHC.Real
infixr 8 ^
優(yōu)先級和結合性規(guī)則的組合通常稱之為固定性(fixity)規(guī)則。
Haskell的標準庫prelude定義了至少一個大家熟知的數(shù)學常量。
ghci> pi
3.141592653589793
然后我們很快就會發(fā)現(xiàn)它對數(shù)學常量的覆蓋并不是很廣泛。讓我們來看下Euler數(shù),e。
ghci> e
<interactive>:1:0: Not in scope: `e'
啊哈,看上去我們必須得自己定義。
不要擔心錯誤信息
以上“not in the scope”的錯誤信息看上去有點令人畏懼的。別擔心,它所要表達的只是沒有用e這個名字定義過變量。
使用ghci的let構造器(contruct),我們可以定義一個臨時變量e。
ghci> let e = exp 1
這是指數(shù)函數(shù)exp的一個應用,也是如何調用一個Haskell函數(shù)的第一個例子。像Python這些語言,函數(shù)的參數(shù)是位于括號內的,但Haskell不要那樣。
既然e已經(jīng)定義好了,我們就可以在數(shù)學表達式中使用它。我們之前用到的乘方操作符(^)是對于整數(shù)的。如果要用浮點數(shù)作為指數(shù),則需要操作符(**)。
ghci> (e ** pi) - pi
19.99909997918947
Note
這是ghci的特殊語法
ghci 中 let 的語法和常規(guī)的“top level”的Haskell程序的使用不太一樣。我們會在章節(jié)“初識類型”里看到常規(guī)的語法形式。
有時候最好顯式地加入一些括號,即使Haskell允許省略。它們會幫助將來的讀者,包括我們自己,更好的理解代碼的意圖。
更加重要的,基于操作符優(yōu)先級的復雜的表達式經(jīng)常引發(fā)bug。對于一個簡單的、沒有括號的表達式,編譯器和人總是很容易的對其意圖產生不同的理解。
不需要去記住所有優(yōu)先級和結合性規(guī)則:在你不確定的時候,加括號是最簡單的方法。
在大多數(shù)系統(tǒng)中,ghci有些命令行編輯的功能。如果你對命令行編輯還不熟悉,它將會幫你節(jié)省大量的時間。基本操作對于類Unix系統(tǒng)和Windows系統(tǒng)都很常規(guī)。按下向上方向鍵會顯示你輸入的上一條命令;重復輸入向上方向鍵則會找到更早的一些輸入??梢允褂?strong>向左和向右方向鍵在當前行移動。在類Unix系統(tǒng)中(很不幸,不是Windows),制表鍵(tab)可以完成輸入了一部分的標示符。
[譯者注:]制表符的完成功能其實在Windows下也是可以的。
Tip
哪里可以找到更多信息
我們只是蜻蜓點水般的介紹了下命令行編輯功能。因為命令行編輯系統(tǒng)可以讓你更加有效的工作,你可能會覺得進一步的學習會有幫助。
在類Unix系統(tǒng)下,ghci使用功能強大并且可定制化的GNU readlinelibrary 。在Windows系統(tǒng)下,ghci的命令行編輯功能是由doskeycommand 提供的。
一個列表由方括號以及被逗號分隔的元素組成。
ghci> [1, 2, 3]
[1,2,3]
Note
逗號是分隔符,不是終結符
有些語言在表示列表時會在右中括號前多一個逗號,但是Haskell沒有這樣做。如果多出一個逗號(比如 [1,2,] ),則會導致編譯錯誤。
列表可以是任意長度??樟斜肀硎境蒣]。
ghci> []
[]
ghci> ["foo", "bar", "baz", "quux", "fnord", "xyzzy"]
["foo","bar","baz","quux","fnord","xyzzy"]
列表里所有的元素必須是相同類型。下面例子我們違反了這個規(guī)則:列表中前面兩個是Bool類型,最后一個是字符類型。
ghci> [True, False, "testing"]
<interactive>:1:14:
Couldn't match expected type `Bool' against inferred type `[Char]'
Expected type: Bool
Inferred type: [Char]
In the expression: "testing"
In the expression: [True, False, "testing"]
這次ghci的錯誤信息也是同樣的很詳細。它告訴我們無法把字符串轉換為布爾類型,因此無法定義這個列表表達式的類型。
如果用列舉符號(enumerationnotation)來表示一系列元素,Haskell則會自動填充內容。
ghci> [1..10]
[1,2,3,4,5,6,7,8,9,10]
字符..在這里表示列舉(enumeration)。它只能用于那些可以被列舉的類型。因此對于字符類型來說這就沒意義了。比如對于["foo".."quux"],沒有任何意思,也沒有通用的方式來對其進行列舉。
順便提一下,上面例子生成了一個閉區(qū)間,列表包含了兩個端點的元素。
當使用列舉時,我們可以通過最初兩個元素之間步調的大小,來指明后續(xù)元素如何生成。
ghci> [1.0,1.25..2.0]
[1.0,1.25,1.5,1.75,2.0]
ghci> [1,4..15]
[1,4,7,10,13]
ghci> [10,9..1]
[10,9,8,7,6,5,4,3,2,1]
上述的第二個例子中,終點元素并未包含的列表內,是由于它不屬于我們定義的系列元素。
我們可以省略列舉的終點(end point)。如果類型沒有自然的“上限”(upperbound),那么會生成無窮列表。比如,如果在ghci終端輸入[1..],那么就會輸出一個無窮的連續(xù)數(shù)列,因此你不得不強制關閉或是殺掉ghci進程。在后面的章節(jié)章節(jié)中我們會看在Haskell中無窮數(shù)列經(jīng)常會用到。
Note
列舉浮點數(shù)時要注意的
下面的例子看上并不那么直觀
ghci> [1.0..1.8]
[1.0,2.0]
為了避免浮點數(shù)舍入的問題,Haskell就從 1.0 到 1.8+0.5 進行了列舉。
對浮點數(shù)的列舉有時候會有點特別,如果你不得不用,要注意。浮點數(shù)在任何語言里都顯得有些怪異(quirky),Haskell也不例外。
有兩個常見的用于列表的操作符。連接兩個列表時使用(++)。
ghci> [3,1,3] ++ [3,7]
[3,1,3,3,7]
ghci> [] ++ [False,True] ++ [True]
[False,True,True]
更加基礎的操作符是(:),用于增加一個元素到列表的頭部。它讀成“cons”(即“construct”的簡稱)。
ghci> 1 : [2,3]
[1,2,3]
ghci> 1 : []
[1]
你可能會嘗試[1,2]:3給列表末尾增加一個元素,然而ghci會拒絕這樣的表達式并給出錯誤信息,因為(:)的第一個參數(shù)必須是單個元素同時第二個必須是一個列表。
如果你熟悉Perl或是C語言,你會發(fā)現(xiàn)Haskell里表示字符串的符號很熟悉。
雙引號所包含的就表示一個文本字符串。
ghci> "This is a string."
"This is a string."
像其他語言一樣,那些不顯而易見的字符(hard-to-see)需要“轉意”(escaping)。Haskell中需要轉意的字符以及轉意規(guī)則絕大大部分是和C語言中的情況一樣的。比如'\n'表示換行,'\t'表示制表符。完整的詳細列表可以參照附錄B:字符,字符串和轉意規(guī)則 。
ghci> putStrLn "Here's a newline -->\n<-- See?"
Here's a newline -->
<-- See?
函數(shù)putStrLn用于打印一個字符串。
Haskell區(qū)分單個字符和文本字符串。單個字符用單引號包含。
ghci> 'a'
'a'
事實上,文本字符串是單一字符的列表。下面例子展示了表示一個短字符串的痛苦方式,而ghci的顯示結果卻是我們很熟悉的形式。
ghci> let a = ['l', 'o', 't', 's', ' ', 'o', 'f', ' ', 'w', 'o', 'r', 'k']
ghci> a
"lots of work"
ghci> a == "lots of work"
True
""表示空字符串,它和[]同義。
ghci> "" == []
True
既然字符串就是單一字符的列表,那么我們就可以用列表的操作符來構造一個新的字符串。
ghci> 'a':"bc"
"abc"
ghci> "foo" ++ "bar"
"foobar"
盡管前面的內容里提到了一些類型方面的事情,但直到目前為止,我們還沒有使用ghci進行過任何類型方面的交互:即使不告訴ghci輸入是什么類型,它也會很高興地接受傳給它的輸入。
需要提醒的是,在Haskell里,所有類型名字都以大寫字母開頭,而所有變量名字都以小寫字母開頭。緊記這一點,你就不會弄錯類型和變量。
我們探索類型世界的第一步是修改ghci,讓它在返回表達式的求值結果時,打印出這個結果的類型。使用 ghci 的:set命令可以做到這一點:
Prelude> :set +t
Prelude> 'c' -- 輸入表達式
'c' -- 輸出值
it :: Char -- 輸出值的類型
Prelude> "foo"
"foo"
it :: [Char]
注意打印信息中那個神秘的 it :這是一個有特殊用途的變量,ghci將最近一次求值所得的結果保存在這個變量里。(這不是Haskell語言的特性,只是 ghci 的一個輔助功能而已。)
Ghci 打印的類型信息可以分為幾個部分:
以下是另一個我們已經(jīng)見過的類型:
Prelude> 7 ^ 80
40536215597144386832065866109016673800875222251012083746192454448001
it :: Integer
Haskell 的整數(shù)類型為 Integer 。 Integer類型值的長度只受限于系統(tǒng)的內存大小。
分數(shù)和整數(shù)看上去不太相同,它使用 %操作符構建,其中分子放在操作符左邊,而分母放在操作符右邊:
Prelude> :m +Data.Ratio
Prelude Data.Ratio> 11 % 29
11 % 29
it :: Ratio Integer
這里的 :m 是 :module 的縮寫,用于載入一個給定模塊。Ghci還提供了很多這類縮寫,方便使用者。
為了方便起見, ghci 給很多命令都提供了縮寫,這里的 :m 就是 :module的縮寫,它用于載入給定的模塊。
注意這個分數(shù)的類型信息:在 :: 的右邊,有兩個單詞,分別是 Ratio 和Integer,可以將這個類型讀作“由整數(shù)構成的分數(shù)”。這說明,分數(shù)的分子和分母必須都是整數(shù)類型,如果用一些別的類型值來構建分數(shù),就會造成出錯:
Prelude Data.Ratio> 3.14 % 8
<interactive>:8:1:
Ambiguous type variable `a0' in the constraints:
(Fractional a0)
arising from the literal `3.14' at <interactive>:8:1-4
(Integral a0) arising from a use of `%' at <interactive>:8:6
(Num a0) arising from the literal `8' at <interactive>:8:8
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `(%)', namely `3.14'
In the expression: 3.14 % 8
In an equation for `it': it = 3.14 % 8
Prelude Data.Ratio> 1.2 % 3.4
<interactive>:9:1:
Ambiguous type variable `a0' in the constraints:
(Fractional a0)
arising from the literal `1.2' at <interactive>:9:1-3
(Integral a0) arising from a use of `%' at <interactive>:9:5
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `(%)', namely `1.2'
In the expression: 1.2 % 3.4
In an equation for `it': it = 1.2 % 3.4
盡管每次都打印出值的類型很方便,但這實際上有點小題大作了。因為在一般情況下,表達式的類型并不難猜,或者我們并非對每個表達式的類型都感興趣。所以這里用 :unset 命令取消對類型信息的打?。?
Prelude Data.Ratio> :unset +t
Prelude Data.Ratio> 2
2
取而代之的是,如果現(xiàn)在我們對某個值或者表達式的類型不清楚,那么可以用:type 命令顯式地打印它的類型信息:
Prelude Data.Ratio> :type 'a'
'a' :: Char
Prelude Data.Ratio> "foo"
"foo"
Prelude Data.Ratio> :type it
it :: [Char]
注意 :type并不實際執(zhí)行傳給它的表達式,它只是對輸入進行檢查,然后將輸入的類型信息打印出來。以下兩個例子顯示了其中的區(qū)別:
Prelude Data.Ratio> 3 + 2
5
Prelude Data.Ratio> :type it
it :: Integer
Prelude Data.Ratio> :type 3 + 2
3 + 2 :: Num a => a
在前兩個表達式中,我們先求值 3+2 ,再使用 :type 命令打印 it的類型,因為這時 it 已經(jīng)是 3+2 的結果 5 ,所以 :type打印這個值的類型 it::Integer 。
另一方面,最后的表達式中,我們直接將 3+2 傳給 :type ,而 :type并不對輸入進行求值,因此它返回表達式的類型 3+2::Numa=>a 。
第六章會介紹更多類型簽名的相關信息。
以下是一個用 Haskell寫的行計數(shù)程序。如果暫時看不太懂源碼也沒關系,先照著代碼寫寫程序,熱熱身就行了。
使用編輯器,輸入以下內容,并將它保存為 WC.hs :
-- file: ch01/WC.hs
-- lines beginning with "--" are comments.
main = interact wordCount
where wordCount input = show (length (lines input)) ++ "\n"
再創(chuàng)建一個 quux.txt ,包含以下內容:
Teignmouth, England
Paris, France
Ulm, Germany
Auxerre, France
Brunswick, Germany
Beaumont-en-Auge, France
Ryazan, Russia
然后,在 shell 執(zhí)行以下代碼:
$ runghc WC < quux.txt
7
恭喜你!你剛完成了一個非常有用的行計數(shù)程序(盡管它非常簡單)。后面的章節(jié)會繼續(xù)介紹更多有用的知識,幫助你(讀者)寫出屬于自己的程序。
[譯注:可能會讓人有點迷惑,這個程序明明是一個行計數(shù)(line count)程序,為什么卻命名為 WC(word count)呢?實際上,在接下來的練習小節(jié)中,讀者需要對這個程序進行修改,將它的功能從行計數(shù)改為單詞計數(shù),因此這里程序被命名為 WC.hs 。]
更多建議: