haskell入門

斯坦福公開課《編程範式》中介紹了Scheme(可是不只僅是Scheme,它只是做爲函數式語言的表明),最後一課介紹了Haskell。。。python

「Hello World!」是學習一門語言的魔咒 :)編程

ghc windows上面的winghciwindows

 
這是一個解釋器環境,和python的差很少
 
在提示符後Prelude>後面輸入
 
"Hello World"
 
解釋器返回 "Hello World",哦耶...
 
固然,你能夠輸入一些你能想到的功能試試,1 + 一、7/2 ...
 
可是試試 5 mod 3 ... 額...
 
別忘了,童鞋們,這個是函數式語言,其構成能夠寫成:函數名 參數列表,函數的返回值纔是你輸出的值(之因此容許 1 + 1, 只是語法糖而已)
 
好比: 1+1,應該寫成 (+) 1 1, (+) 的括號不能少... 由於+這個符號不是一個合法的函數命名
 
其意義是, 調用了一個叫「+」的函數,傳入了兩個參數,分別是1,1, 函數執行以後,返回的結果爲2
 
因此,上面的5 mod 3 應該是 mod 5 3,返回2...
 
來看看list,[1, 2, 3, 4, 5]就是一個list,或者[1, 2..20]也是,相似於ptyhon的range(start,stop,[step]),如:
range(1,21)返回1-20.
 

*Main> [1,2..20]
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
*Main> [1..20]
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]函數

你還能夠[1.2, 1.6..2.1]、[1.0,0.9..0.0]...

*Main> [1.2,1.6..2.1]
[1.2,1.6,2.0]學習

 
固然,目前這個只能線性的,假如你想輸出2, 4, 8, 16, 32...,這個就不能簡單搞定了...(其實也很簡單...用一下map和lambda就行)
 
list的一些經常使用操做:
 
length [1, 2, 3, 4] 獲得 4
take 2 [1, 2, 3, 4] 獲得 [1, 2]
drop 2 [1, 2, 3, 4] 獲得 [3, 4]
head [1, 2, 3, 4] 獲得 1
tail [1, 2, 3, 4] 獲得 [2, 3, 4]
[1, 2, 3, 4] !! 2 獲得 3 (這個是下標操做)
 
來看看函數, 新建個文件,好比:helloworld.hs,而後輸入:
 
hello = "Hello World!"
 
在GHCi中File -> Load或者使用命令:load "文件名",載入文件
 
而後在提示符輸入:hello,獲得結果Hello World
 
來寫個1加到N的函數
 
sumToN n = sum [1..n]
 
函數名是sumToN,接收一個參數n,使用內置函數sum,而後構造一個從1到n的列表,做爲sum的參數
 
若是你好奇sum如何實現,一種簡單的實現能夠爲:
 
sum xs = (+) (head xs) (sum (tail xs))
 
你會發現,原來的循環結構被遞歸取代,一樣會發現,與其想象每一小步操做如何運做(命令式),不如想一想你要計算的結果是如何「定義」的(函數式)
 
來一些有if...then...else的吧
 
isSorted,用來判斷一個list是不是升序的(暫且這樣,後面能夠傳入比較函數,泛化這個函數)
 
假如傳入的參數是 [](空list)或者只有一個元素,那麼返回True
 
能夠寫成
isSorted [] = True
isSorted (x:[]) = True(參數 (x:xs)的意義是:假設傳入list ns,x是head ns,xs是tail ns) 
 
這個相似於編譯原理裏面的產生式,在Haskell中被稱爲模式匹配...意思就是拿參數跟全部的函數簽名進行匹配(固然是我所說的只拿函數參數匹配的前提是函數名我確認是isSorted了),順序是從上到下
 
說好的if...else來了
完整的爲:
isSorted [] = True
isSorted (x:[]) = True
isSorted n = if (head n > (n !! 1)) then False
else isSorted (tail n)
 
其實代碼就是再定義什麼是Sorted
1. 若是列表爲空,是sorted
2. 若是列表只有一個元素,是sorted
3. 若是第一個元素比第二個元素大,那麼不是sorted,不然sorted依賴於剩下的元素是否sorted
 
再搞一個half函數,功能就是將一個list分紅兩半,首先搞一個這樣的:
 
half :: [b] -> [[b]]
half [] = [[]]
half x | (/=) (mod (length x) 2) 0 = [[]]
| otherwise = (take n x) : (drop n x) : []
where {
n = div (length x) 2
}

 

第一句,::是定義了這個函數的簽名...即輸入一個list,返回一個list的list...,這一句不是必須的,由於強大的Haskell能夠幫助你推斷類型...(這個好多書都放到前面講,我以爲放到後面說比較合適,由於我的以爲一開始跟少人關心Haskell的類型系統,起碼我是這樣的)
第二句爲空判斷,以前已經搞過了
第三句「=」前面的部分是匹配條件
 
(/=) (mod (length x) 2) 0 = [[]]("/="意思是不等於...至關於 != 或者 <>)
的意思是,若是x的長度不爲偶數,則返回[[]]
 
otherwise是除了上述條件外,其它的狀況
(take n x) : (drop n x) : []
(:) 是個函數...其實應該寫成 (:)  (take n x) ((:)  (drop n x) [])
其做用是,將一個元素加入到一個list的中,好比:(:) 1 [2, 3, 4]獲得[1, 2, 3, 4]
 
這裏是將兩個list合併爲一個list(list)中...
 
關於n,其實簡化以前應該是: (take ( div (length x) 2 ) x) : (drop ( div (length x) 2 ) x) : []
 
因爲一樣的式子計算兩遍有些惋惜,並且不利於表達「定義」,因此,使用了where,在其中定義了n
 
切記,where不該該當作定義變量來使用,並且當作存儲遞歸結果,加速計算來使用
 
在遞歸式中,有些遞歸結果在前面的遞歸中已經計算過,有些計算量很大,則可使用where在緩衝,加速計算
 
上述half只是爲了使用 「|」 操做符來區分一下匹配過程,其實也能夠支持list長度爲奇數的狀況...
 
half :: [b] -> [[b]]
half [] = [[]]
half x = (take n x) : (drop n x) : []
where {
n = div (length x) 2
}
 
先到這吧,後面還有挺多東西的...
 
其實語法不是關鍵,關鍵是將編程的思考模式轉換到函數式上...
 
你們可使用上面的只是寫個排序...固然,你會發現一些問題...或者說,你無心間發現了函數式的一些特性...

 轉自:http://emavaj.blog.163.com/blog/static/1332805572013741013704/spa

相關文章
相關標籤/搜索