Haskell
with UPenn CIS 194: Introduction to Haskell (Spring 2013)
and with Algebra of Programming (Richard Bird & Oege de Moor)
基本语法
- 操作符
==等于/=不等于++两个列表相加:向列表前加入一个元素--或{- ... -}注释$apply 分隔函数和参数(类似于括号)where在alternatives中用于定义重复使用的变量
- 列表
list[ .. ]- 自动填充,如
[1..10] - 列表中的元素必须是相同类型
head首个元素tail除首个元素之外的部分(作为一个列表返回)null List检查List中是否有元素null:: [a] -> Boolreverse List将List反转take num List返回List前num个元素(作为一个列表)drop num List删除List中前num个元素,并返回操作后的列表(如果num大于等于列表长度则返回空列表)min List返回列表中最小值sum List返回列表元素之和product返回列表元素之积listName !! index下标运算符ele ·elem· List判断元素ele是否在列表List中,·notElem·相反cycle List / repeat Ele利用列表List或者元素Ele生成无线列表replicate num Ele得到Ele重复num次构成的列表lines :: String → [String]将一段内容分行,可以用map func . lines表示对每行施加函数func
Tuple (ele1, ele2, ...)- fixed-size collection of values
- each value can have a different type
- 列举类型的元素
data DataType = xxx ; | xxx ; | xxx; ... ; deriving (Eq,Show) - 说明
:info (operator):type ele判断元素的类型:set prompt "ghci>"修改提示符设置
- 函数
funcname args = ...- 函数首字母不能大写
:| filename装载中的函数以供使用- 本质上,Haskell的函数都只有一个参数,所有多个参数的函数都是Curry函数,先返回取第一个数为参数的函数,然后再以第二个数为参数调用它
- 用不全的参数调用函数可以创造新的函数
- Haskell高阶函数
- Type constructor
data TypeName = Constructor ... ; deriving (Show)- newtype TypeName = Constructor Field – – different from data keyword, newtype can only have one constructor and exactly one field.
- if-then-else 中 else 不可忽略
Haskell模块
- 加载模块
import moduleName(e.g.Data.List):m modName1 modName2 modName3- 加载模块中的函数
import modName (funcName1, funcName2 - 除某个函数以外加载
import modName hiding (funcName) - 防止重名,要求全名指定
import qualified modName1 - 库重命名
import quantified modName as varName
- 用Hoogle检索函数 https://hoogle.haskell.org/
- 常用模块
- Prelude
- Prelude is a module with a bunch of standard definitions that gets implicitely imported into every Haskell program.
data Maybe a = Nothing | Just a: A useful polymorphic type, either contains a value of type a (wrapped in the Just constructor), or it is nothing (representing some sort of failure or error)
- Data.List
intersperce ele List将元素ele置于List每两个元素之间intercalate List1 List2将List1置于List2每两个元素之间transpose视列表的列表为矩阵进行转置操作any/orboolFunc List检查元素符合条件takeWhile boolFunc List遇到false停止 (类似函数有span,break)delete ele List删掉该List中首次出现的这一元素List1 \\ List2差集操作List1-List2List1 ·union· List2并集(遍历List2,若某元素不属于List1,则追加到List1后)List1 ·intersection· List2交集
- Data.Char
- 字符串的本质就是一组字符的List,所以往往会在
filter或是map字符串时用到 generalCategory函数返回值是情况的枚举(参考Ordering LT, GT, EQ)
- 字符串的本质就是一组字符的List,所以往往会在
- Prelude
- Haskell 输入与输出
main = putStrLn "hello, world"putStrLn型态为IO(),putStr()不打印换行,putStr()由putChar()递归定义得到putStr(x:xs) = do ; putChar x ; putStr xs- 一个I/O action会在绑定到
main并执行程序的时候被触发 - 用
do表示法将所有的I/O action绑成一个 - 读出内容
var<-getLine - 注意区分:
oper=getLine只是为getLine取了一个别名 when在Control.Monad中,必须import才能得到- 接受boolean值跟I/O action,如果True,就回传所给的I/O
action,否则回传
return()
- 接受boolean值跟I/O action,如果True,就回传所给的I/O
action,否则回传
sequence接受一串I/O action,并回传会依序执行他们的I/O action(sequence :: [IO a] -> IO[a])forever在Control.Monad中,回传一个永远作同一件事的I/O action- 文件流
getContents标准输入读取至EOF。惰性I/O,并不会马上读取所有输入 - 读取文件
handle <- openFile fileName ReadMode ; contents <- hGetContents handle ; ... ; hClose handle ; (openFile :: FilePath -> IOMode -> IO Handle) - 其中,
openFile,ReadMode,hGetContents,hClose;type FilePath = String,data IOMode = ReadMode | WriteMode | AppendMode | ReadWriteMode - 或者用
contents <- readFile fileName读取文件,无需考虑句柄的关闭 - Map implementation:
1
2
3map :: (a, b) → [a] → [b]
map _ [] = []
map f (x:xs) = f x : map f xs - Filter implementation:
1
2
3
4
5filter :: (a → Bool) → [a] → [a]
filter _ [ ] = [ ]
filter p (x:xs)
| p x = x : filter xs
| otherwise = filter xs - Fold implementation. e.g.
fold (+) 0 [1,2,3,4,5] => (1+(2+(3+(4+(5+0)))))1
2
3foldr :: (a → b → b) → b → [a] → b
foldr _ z [ ] = z
foldr f z (x:xs) = f x (foldr f z xs)
UPenn CIS 194 2013
Week 2: Type Construct
- Enumeration types:
data TypeName = ele1 ; | ele2 ; … ; deriving (Show, Eq, … )data AlgDataType = Constr1 Type11 Type12; | Constr2 Type 21 ; … ; deriving (Show, Eq , …)func :: type1 → type2 ; func ele1 = ele2 ; func ele3 = ele4 ; … ; func _ = rest
Week 4: Higher-order programming and type inference
- Anonymous functions (lambda abstraction)
- Here is an example
1
2
3
4greaterThan100 [1, 9, 349, 6, 907] = [349, 907]
greaterThan100 :: [Integer] → [Integer]
greaterThan100 xs = filter (\x → x > 100) xs
Or equivalent: greaterThan199 xs = filter (>100) xs \is supposed to be as lambda, function\x -> x > 100outputs whether x is greater than 100(>100)is an operator section:?yis equivalent to\x -> x ? y, andy?Is equivalent to\x -> y ? x
- Here is an example
- Function composition
(f.g)- useful in writing concise, elegant code
- Currying and partial application
\x y z ->is syntax for\x -> (\y -> (\z -> ... ))
- Wholemeal programming
```Haskell foobar :: [Integer] → Integer foobar [] = 0 foobar (x:xs) | x > 3 = (7*x+2) + foobar xs | otherwise = foobar xs
foobar’ :: [Integer] → Integer foobar’ = sum . map (-> 7*x + 2) . filter (>3)
1
2
3
4
5
6
7- Avoid the problem of doing too much at once and working at too low of a level.
- This defines foobar' as a "pipeline" of three functions. First filter, then apply to every element, eventually sum them up.
- Folds
- ```Haskell
fold :: b → (a → b → b) → [a] → b
fold z f [] = z
fold z f (x:xs) = f x (fold z f xs)fold is already provided in the standard Prelude, under the name of
foldr :: (a→b→b) → a → [a] → bThere is also
foldl, which folds from the left (usefoldl'from Data.List is more efficient)
Week 5: More Polymorphism and Type Classes
- Parametricity
a -> a -> ais a promise thatafunction with this type will work no matter what type the caller chooses, otherwise specify the type
- Type classes
- Num, Eq, Ord and Show are type classes, and we say that
(==),(<),(+)are "type-class polymorphic". deriving (Eq, Ord, Show)Tell GHC to automatically derive instances of theEq,Ord, andShowtype classes for our data type.
- Num, Eq, Ord and Show are type classes, and we say that
- Standard type classes
- Ord: totally ordered, any two elements can be compared to see which is less than the other.
- Num: numeric types, support things like addition, subtraction, and multiplication.
- Show: defines the method Show, which is used to convert values into Strings
- Read: the dual of Show
- Integal: represents whole number types such as Int and Integer
Week 6: Lazy Evaluation
- Strict evaluation
- Opposite to lazy evaluation, function arguments are completely evaluated before passing them to the function.
- Consequences
- Purity
- To the recursion function, whether the list should be recursed before processed, or computed first before unwinding.
- For example, foldl’ requires the second argument to be evaluated before it proceeds, so a large thunk never builds up (compared with function foldl).
- Infinite data structures
- Lazy evaluation means that we can work with inifinite data structures. Defining an infinite data structure actually only creates a thunk, which we can think of as a “seed”, out of which the entire data structure can potentially grow.
- Dynamic programming
- One must take great care to fill in entries of a dynamic programming table in the proper order, so that its dependencies have already been computed. If we get the order wrong, we gor bogus results.
Week 8: I/O
mainitself is an I/O action with type IO()dodefines a sequence of actions- Combining IO
(>>) :: IO a -> IO b -> IO b––running two input computation in sequence