Haskell 学习笔记 (3)
- 导入模块
import Data.List
- 导入模块必须放置在任何函数的定义之前
- 导入模块后,模块内的函数就进入了全局命名空间
- GHCi 导入模块
:m + Data.List Data.Map Data.Set
- 导入部分函数
import Data.List (nub, sort)
- 忽略部分函数
import Data.List hiding (nub)
- 限定导入
import qualified Data.Map
- 限定导入后的函数需要指定前缀
Data.Map.filter
- 限定导入可以使用别名
import qualified Data.Map as M
import Data.List
numUniques :: (Eq a) => [a] -> Int
numUniques = length . nub
foldl
左折叠在执行过程中构建了一个大的延迟计算栈,直到折叠的目标变成 []
之后,才真正开始对先前延迟的进行求值。对于大列表来说,这就容易造成栈溢出,或者内存占用过多。使用 Data.List.foldl'
可以进行严格左折叠。两个函数的计算过程类似:
foldl (+) 0 [1,2,3]
= foldl (+) (0+1) [2,3]
= foldl (+) ((0+1)+2) [3]
= foldl (+) (((0+1)+2)+3) []
-- The above will not cause stack overflow
-- because they are allocated on the heap.
-- However, the following will
-- because all operands will be pushed to the stack.
= ((0+1)+2)+3
= (1+2)+3
= 3+3
= 6
foldl' (+) 0 [1,2,3]
= foldl' (+) 1 [2,3]
= foldl' (+) 3 [3]
= foldl' (+) 6 []
= 6
Maybe
数据类型
findKey :: (Eq k) => k -> [(k,v)] -> Maybe v
findKey key xs = foldr (\(k,v) acc -> if key == k then Just v else acc) Nothing xs
phoneBook =
[("betty", "555-2938")
,("patsy", "493-2928")
,("wendy", "939-8282")
]
findKey "patsy" phoneBook -- Just "493-2928"
findKey "penny" phoneBook -- Nothing
- 编写模块
- 要导出的部分写在
moudle
里面
-- Geometry/Sphere.hs:
module Geometry.Sphere
( volume
, area
) where
volume :: Float -> Float
volume radius = (4.0 / 3.0) * pi * (radius ^ 3)
area :: Float -> Float
area radius = 4 * pi * (radius ^ 2)
-- Geometry/Cuboid.hs
module Geometry.Cuboid
( volume
, area
) where
volume :: Float -> Float -> Float -> Float
volume a b c = rectArea a b * c
area :: Float -> Float -> Float -> Float
area a b c = rectArea a b * 2 + rectArea a c * 2 + rectArea c b * 2
rectArea :: Float -> Float -> Float
rectArea a b = a * b
-- Use:
import qualified Geometry.Sphere as Sphere
import qualified Geometry.Cuboid as Cuboid
Sphere.area 10
Cuboid.area 10 10 10
data
定义新的数据类型,等号左端的部分为类型名称,等号右端的为值构造器- 类型名和值构造器首字母必须大写
- 一个值构造器可以有若干字段
deriving (Show)
会将该类型置于Show
类型类之中- 在一个类型仅有唯一值构造器时,类型名与值构造器名称相同是非常常见的
- 可以编写人民喜闻乐见的辅助函数
data Point = Point Float Float deriving (Show)
data Shape = Circle Point Float | Rectangle Point Point deriving (Show)
area :: Shape -> Float
area (Circle _ r) = pi * r ^ 2
area (Rectangle (Point x1 y1) (Point x2 y2)) = (abs $ x2 - x1) * (abs $ y2 - y1)
area (Rectangle (Point 0 0) (Point 100 100)) -- 10000.0
area (Circle (Point 0 0) 10) -- 314.15927
nudge :: Shape -> Float -> Float -> Shape
nudge (Circle (Point x y) r) dx dy = Circle (Point (x+dx) (y+dy)) r
nudge (Rectangle (Point x1 y1) (Point x2 y2)) dx dy = Rectangle (Point (x1+dx) (y1+dy)) (Point (x2+dx) (y2+dy))
baseCircle :: Float -> Shape
baseCircle r = Circle (Point 0 0) r
baseRect :: Float -> Float -> Shape
baseRect width height = Rectangle (Point 0 0) (Point width height)
makeCircle :: Float -> Float -> Float -> Shape
makeCircle x y r = nudge (baseCircle r) x y
makeRect :: Float -> Float -> Float -> Float -> Shape
makeRect x1 y1 width height = nudge (baseRect width height) x1 y1
makeRect 60 23 40 100 -- Rectangle (Point 60.0 23.0) (Point 100.0 123.0)
- 使用记录类型
data Car = Car { company :: String
, model :: String
, year :: Int
} deriving (Show)
tellCar :: Car -> String
tellCar (Car {company = c, model = m, year = y}) =
"This " ++ c ++ " " ++ m ++ " was made in " ++ show y
mycar = Car {company="Ford", model="Mustang", year=1967}
tellCar mycar -- "This Ford Mustang was made in 1967"