Haskell學習筆記<三>


…高階函數

map :: (a->b) ->[a] ->[b],將函數f依次應用於序列[a],得到新的序列[b]。

filter :: (a->bool)->[a]->[a],利用函數f過濾序列[a]。

這兩個函數都可用list comprehension來實現,不過在某些情況下更簡潔。利用這兩個函數和CF組合可以生成各種需要的函數。

lambda

著名的lambda表達式(C++11中引入),也就是匿名函數,某些僅使用一次的函數不必命名,為了使代碼更簡潔,就有了lambda表達式。其格式為:

\ para1 para2->(return value)

\ (para1,para2) -> (return value)

由於Haskell有自動類型推斷,所以不必明確表明返回類型。注意這里直接return value了,也就無法使用模式匹配之類的。

折疊

折疊是對list處理模式的再抽象。所有遍歷list中元素並據此返回一個值的操作都可以交給fold實現。

foldl即為左折疊,從list左端開始。其參數分別是一個二元函數(參數分別是新值、累加值),一個初始值,一個待處理的list。

foldr為右折疊,由於模式匹配的時候一般不使用++,這時候就會用:配合foldr來完成任務。另外foldr適合處理無限長的list。

foldl1將參數中的初始值去掉,自動以list的head元素作為初始值;foldr1類似,取的是最后的元素。

scanl、scanr與fold系列類似,只是累加值的狀態會被記錄到下一次累加中(sum即scanl (+))。

$

$是函數調用符,與空格不同的是它的優先級最低,且為右結合,設計這個操作符的目的只是讓某些函數寫起來更簡單。比如 sqrt (1+2+3),可以簡單寫成sqrt$1+2+3

函數組合

函數組合對應着數學中的復合函數。如果想要生成新的函數,使用函數組合操作符"."可能會很方便。"."具有右結合性,右邊函數的返回值類型必須與左邊函數的參數值類型相符。它的作用類似於管道操作符,將先進行的運算結果傳給前面的函數。顯然函數組合只適用於只有一個參數的函數之間。一般也是用於簡潔化書寫。

Haskell是偏於數學的高等抽象語言,因此以上這些特性內置在語言中,只是給coders提供了一些更優雅的書寫方式,用前面學過的list comprehension都可以完成相同的功能,只是沒有那么優雅了╮(╯-╰)╭

第七章 模塊

前面六章主要介紹了函數,身為FP,函數顯然是最重要的組成部分。但是作為一門編程語言,一些必備的特性也會出現在Haskell中,例如:庫。

Haskell中的模塊是由一組相關的函數,類型和類型類組成的。程序的架構就是由主模塊調用其他模塊(類似C),前面介紹的函數都是裝載在prelude中的。

導入模塊的語法類似java,import xxx(在ghci中是:m xxx,可以一次導入多個),如果只是導入一部分函數,可以在模塊名后面在上(fun1,fun2..),如果要去除某一函數,可以在模塊名后面加上hiding (funx),后者主要是為了避免命名沖突。

避免命名沖突還有一個方法,就是加上限定符(類似C++),使用import qualified module_name as name1,關鍵字 qualified表面后面的模塊必須加上限定名,as則可以為限定符起別名。 下面介紹標准庫的常用模塊:

Data.List

顯然這里是前文介紹的所有list操作函數所在的庫。下面是一個簡表:

函數原型

解釋

intersperse :: a- > [a]- > [a]

將第一個參數插入list相鄰的元素之間

intercalate :: [a] -> [[a]] -> [a]

將第一個List交叉插入第二個List中間

transpose :: [[a]] -> [[a]]

反轉一組List的List,類似轉置矩陣

foldl' & foldl1'

非惰性版的foldl和foldl1,大list的時候用

concat :: [[a]] -> [a]

合並list中的元素,可用來追加字符串

concatMap :: (a -> [b]) -> [a] -> [b]

map一個list,然后concat

and(or) :: [Bool] -> Bool

對一組bool做與(或)運算

any(all) :: (a -> Bool) -> [a] -> Bool

一組元素中滿足條件的元素存在(都是)

iterate :: (a -> a) -> a -> [a]

用參數2遞歸調用參數1,產生無限的list

splitAt :: Int -> [a] -> ([a], [a])

在指定下標處切割list,返回一個tuple

takeWhile :: (a -> Bool) -> [a] -> [a]

將滿足條件的前面連續多個元素提取出來

dropWhile :: (a -> Bool) -> [a] -> [a]

將前面不滿足條件的連續多個元素舍棄

span(break) :: (a -> Bool) -> [a] -> ([a], [a])

類似takeWhile,不過將結果切割了,分別從false處、true處斷開

sort :: Ord a => [a] -> [a]

排序,以<順序

group :: Eq a => [a] -> [[a]]

將相鄰並相等的元素分組,配合sort

inits(tails) :: [a] -> [[a]]

遞歸調用init(tail)直到什么都不剩

isInfixOf :: Eq a => [a] -> [a] -> Bool

子序列判定,isPrefixOf、isSuffixOf用於判定首尾序列

elem、notElem

判定是否子元素

partition :: (a -> Bool) -> [a] -> ([a], [a])

過濾元素並分組

find :: (a -> Bool) -> [a] -> Maybe a

返回第一個滿足條件的元素

elemIndex :: Eq a => a -> [a] -> Maybe Int

返回第一個相等元素的索引

elemIndices :: Eq a => a -> [a] -> [Int]

返回所有滿足條件元素的索引集

findIndex :: (a -> Bool) -> [a] -> Maybe Int

返回第一個滿足條件元素的索引

findIndices :: (a -> Bool) -> [a] -> [Int]

返回所有滿足條件元素的索引集

zip,zipWith系列(<=7)

將list對應元素組合成tuple的list

lines :: String -> [String]

將字符串按行分割

unlines :: [String] -> String

line的反函數

words(unwords)

合並單詞集或相反

nub :: Eq a => [a] -> [a]

去除所有重復元素,組成新的list

delete :: Eq a => a -> [a] -> [a]

刪除第一個與之相等的元素

union(intersection) :: Eq a => [a] -> [a] -> [a]

返回兩個list的並(交)集,以第一個為主順序

insert :: Ord a => a -> [a] -> [a]

保持順序的插入元素

   

以上函數中,參數為int的都有更通用的版,在前面加上genernic就可得到通用版(如genericLength);

而用(==)判定相等的函數,可以改成用謂詞作判定依據,只需要在其后加上By,如sortBy,groupBy等。

這里引入了Data.Function中的on函數:on :: (b -> b -> c) -> (a -> b) -> a -> a -> c

f `on` g = \x y -> f (g x) (g y),這個函數可以使By系列的函數使用起來更加簡潔。判斷相等性常用 (==) `on` xxx,判定大小則常用 compare `on` xxx.

Maybe類型是在可能返回nothing時使用,這樣返回時如果存在就用Just xxx的格式,否則返回Nothing

Data.Char

這個模塊主要包含了一些字符處理函數。類似於C中的<ctype.h>

函數原型

解釋

isControl :: Char -> Bool

判斷控制字符

isSpace

判斷空格字符(space、tab、\n)

isLower

判斷小寫字符

isUpper

判斷大寫字符

isAlpha(isLetter)

判斷字母

isAlphaNum

判斷字符或數字

isPrint

判斷可打印字符

isDigit(isNumber)

判斷數字

isOctDigit

判斷八進制數字

isHexDigit

判斷十六進制數字

isMark

判斷Unicode注音(for Frenchman)

isPunctuation

判斷標點符號

isSymbol

判斷貨幣符號

isSeperater

判斷Unicode空格或分隔符

isAscii

判斷unicode字符表前128位

isLatin1

判斷unicode字符表前256位

isAsciiUpper

判斷大寫ascii字符

isAsciiLower

判斷小寫ascii字符

generalCategory :: Char -> GeneralCategory

判斷所在分類

toUpper :: Char -> Char

小寫轉換成大寫,其余不變

toLower

與上面相反

toTitle

將一個字符轉換成title-case

digitToInt(ord)

字符轉換成int值

intToDigit(char)

int轉換成字符

注意這里的函數比C中的字符處理函數要多得多,除了考慮unicode因素外,這里將各種進制的數看做完全不同的東西。也就是說,並不依據計算機內存模型。

Data.Map

這里的map類似C++中的關聯容器std::map.一個list里面全是pair(兩位的tuple)。內部構造是由紅黑樹完成的,鍵值必須可排序。

函數原型

解釋

fromList :: Ord k => [(k, a)] -> Map k a

將一個關聯列表轉換成一個map

insert :: Ord k => k -> a -> Map k a -> Map k a

插入一對鍵值

empty :: Map k a

返回一個空map

null :: Map k a -> Bool

測試一個map是否非空

size :: Map k a -> Int

返回map大小

singleton :: k -> a -> Map k a

由參數構建一個pair(std::make_pair)

lookup :: Ord k => k -> Map k a -> Maybe a

查找鍵,找到后返回對應的值

member :: Ord k => k -> Map k a -> Bool

查找鍵是否存在

map、filter

類似list中的函數,只針對value(與key無關)

keys、elems

返回由key或者value組成的list

toList :: Map k a -> [(k, a)]

由map生成對應的list

fromListWith :: Ord k => (a -> a -> a) -> [(k, a)] -> Map k a

類似於multimap,可以由一個key對應多個鍵值,參數1選擇key值相同的鍵如何處理

insertWith :: Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a

insert的復數版,如果存在相同key,由參數1決定如何處理value

Data.Map里面還有不少函數,常見的操作已經都列舉在上面了。

Data.Set

與STL::set類似的數據結構,鍵值唯一。

函數原型

解釋

fromList :: Ord a => [a] -> Set a

與map中的類似,將list轉化為set

difference :: Ord a => Set a -> Set a -> Set a

返回第一個有第二個沒有的元素集

union :: Ord a => Set a -> Set a -> Set a

取並集

null,size,member,empty,singleton,insert,delete

與map的接口功能類似

isSubsetOf :: Ord a => Set a -> Set a -> Bool

判斷是否子集

isProperSubsetOf :: Ord a => Set a -> Set a -> Bool

判斷是否真子集

map和filter

也類似於map

這里還討論了Data.List.nub的執行效率問題,nub要求List元素具有Eq類型類,而要使用集合來去除重復元素,必須是Ord類型類。后者的執行速度比前者,前者在大list時不如setNub(但是setNub不穩定)。

自定義模塊

自定義模塊的模塊名與文件名必須一致(這點類似matlab中的.m文件)。格式是:

module Xxx

(fun1,fun2..)

where fun1 :: a->b->c

    fun1=…

    fun2::…

注意模塊名首字母大寫。如果要采用分層的方法,則新建一個文件夾,為模塊名(如Data),然后建文件(如List),導入時把整個文件夾放在引用它的文件的同一目錄下。注意聲明的時候前面要加上限定符(如module Data.List)。

雖然module看起來很類似C中間的Struct,但是還是有本質的不同,最明顯的就是它只封裝了一系列的函數,而C中間則只能存放變量。另外就是Haskell並不支持面向對象。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM