[TOC]
假设读者都有函数式编程方面的知识。这个笔记只是记录笔者觉得Haskell 最有特点的几个地方。
概念
变量、表达式、类型、绑定、作用域、模式
基本语法
只写一些容易遗忘和另类的语法。
注释
-- comments
{- comments
multi-lines
-}
表达式
3::[2, 4] -- ==[3,2,4]
case x of 'a' -> 1
'b' -> 2
'c' -> 3
if ... then ... else ...
let x=a in expr
expr where x=a
sgn :: Double -> Double
sgn x | x<0 = -1
| x>0 = 1
| x==0 = 0
类型
f :: Double -> Double
n :: Int
x :: Double
x :: String/Char/Num...
5 :: Num a => a -- environment of types
f x = x+1 :: Num a => a -> a
模块
module Main (
binding,
module YourModule,
DataType(Constructor1,...),
ClassDef(classMethod1,...),
...
) where -- the name of the module
import Data.List -- import an exterial module
import MyModule -- MyModule.foo
import MyModule.SubModule (MyType, myvariable,...) [hiding (...)] -- import some, hind some
import qualified YourModule as YM -- YM.foo
... -- expressions, the body of the module
binding
DataType
...
main :: IO() -- like main function in C and __main__ in python
main = print(1+2)
注.
- Haskell 默认导入Prelude模块
- List 元素类型必须一样
ghci交互
:t x -- type of x
:info x -- information of x
:l m -- load a module
运算符
++ -- concatenate two lists
[1,2,3]!!2 -- 3
fst, snd, head/tail, init/last -- get element(s) in a list
null [] -- is it an empty list?
take, drop, reverse, and/or, elem/notElem -- operate lists
/= -- not equal
数据类型
模式
data Position = Position Double Double
data Person = Person String Int Bool
older :: Person -> Person -> Bool
older Person(a1, b1, c1) Person(a2, b2, c2) = b1 > b2
match Person(a1, b1, c1) Person(a2, b2, c2) = c1 \= c2 && abs(b1-b2)<=2
older p1@Person(a1, b1, c1) p2@Person(a2, b2, c2) = b1 > b2 -- @pattern
data Nat = Zero | Succ Nat -- Zero, Succ: constructor of Nat
记录语法
data Person = Person {getName:: String, getAge:: Int, getGender:: Bool}
p = Person {getName='', getAge=0, getGender=True}
-- exercise
data Person = Person {getName:: String, getAge:: Int, getGender:: Bool}
show_info :: Person -> String
show_info p = "My name is " ++ (getName p) ++ ". I am " ++ (show (getAge p)) ++ " years old."
main = do
print (show_info p) where
p = Person {getName="William", getAge=30, getGender=True}
列表递归
列表的盒子比喻
列表元素类型统一
data [a] = a: [a] | []
1:2:[] == [1,2]
[1,3..7]
head (x:xs) = x -- list pattern
repeat :: a -> [a]
repeat x = x:repeat x
列表操作
map
filter
foldl/foldr
-- foldl f a [b, c] == f(f(a,b),c)
scanl/scanr
元组,高阶函数
元组
元组元素可以有不同类型
(a,b,c)
("Haskell", 1990, True) :: (String, Int, Bool)
高阶函数
(反)Curry化
zip/unzip
zipWith (+) [1,2] [1,3]
-- [2,5]
$ -- application
& -- piple
f $ x == f x == x & f
\x -> f x == f -- dummy function
类型类
class 定义类型类
instance 定义类型类的实例
Eq -- typeclass
class Eq a where -- declaration of Eq
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
instance Eq Person where
(==) :: Person -> Person -> Bool
p == q = getName p == getName q
Show/Read
数字类型类
-- classes related to numbers
Real <= Ord, Num <= Eq
Enum
Bounded
-- number class
RealFloat <= Floating, RealFrac <= Fractional <= Num <= (Eq, Show) -- Num a => Fractional a
Floating <= Integral <= (Real, Enum) <= Num
RealFrac <= Real <= (Num, Ord)
注. Haskell 类型约束信息并不会保存到数据中
Haskell | 数据 | 类型 | 类型类 |
---|---|---|---|
范畴论 | 元素 | 对象/集合 | 子范畴/范畴 |
例子 | 3 | Int | Num/Show/Eq/Hack |
oop | 对象 | 类型 | 元类 |
代数学 | 元素 | 代数系统 | 代数系统类型 |
Haskell 关键词 | 3:: Int | instance,data, type, newtype | class |
类型声明
类型别名、新类型声明
type List a = [a] -- 类型别名, 右侧没有函数
type Function1D = Double -> Double
type Function1D a = a -> a
-- newtype 只接收一个参数
newtype Transform a = Transform (a->a) -- 接近 data (看作 data 特例) 而非 type,比data快速
newtype Const a b = Const a
newtype State s a = State {runState :: s -> (a, s)}
newtype 避免额外的打包解包过程, 右侧包裹的类型必须是上层类型.
惰性求值
概念
-
任务盒(thunk): 只是一个表达式,不进行求值
-
常态(normal form): 求值后的表达式; 弱常态:部分求值, 所有构造函数创建的数据都是若常态
-
底(bottom): \perp
:print -- lookup the evaluation
:sprint
:force
-- 计算到若常态
seq :: a -> b -> a
$!
-- 计算到常态
deepseq
$!!
force :: NFData a => a -> a
网友评论