深入浅出 haskell

30
深深深深 Haskell 深3深

Upload: justin-jenkins

Post on 02-Jan-2016

98 views

Category:

Documents


1 download

DESCRIPTION

深入浅出 Haskell. 第 3 讲. Shape 定义回顾. data Shape = Rectangle Side Side | Ellipse Radius Radius | RtTriangle Side Side | Polygon [ Vertex ] deriving Show type Vertex = (Float,Float) type Side = Float type Radius = Float. Shape. Graphic. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 深入浅出 Haskell

深入浅出 Haskell深入浅出 Haskell

第 3讲

Page 2: 深入浅出 Haskell

Shape定义回顾data Shape = Rectangle Side Side | Ellipse Radius Radius | RtTriangle Side Side | Polygon [ Vertex ] deriving Show

type Vertex = (Float,Float) type Side = Floattype Radius = Float

Page 3: 深入浅出 Haskell

Shape• 度量 :Float

• 单位 :inch

• 度量 :Int

• 单位 :pixel

Graphic 坐标系统

Shape 坐标系统

(200,200) pixelsor(1,-1) inches

(0,0)

(0,0)

(200,0)

(0,200)

(1,0)(-1,0)

(0,1)

(0,-1)

Graphic

Page 4: 深入浅出 Haskell

单位转换inchToPixel :: Float -> IntinchToPixel x = round (100*x)

pixelToInch :: Int -> FloatpixelToInch n = intToFloat n / 100

intToFloat :: Int -> FloatintToFloat n = fromInteger (toInteger n)

Page 5: 深入浅出 Haskell

坐标变换xWin, yWin :: IntxWin = 600yWin = 500

xWin2, yWin2 :: IntxWin2 = xWin `div` 2 yWin2 = yWin `div` 2

trans :: Vertex -> Pointtrans (x,y) = ( xWin2 + inchToPixel x, yWin2 - inchToPixel y )

transList :: [Vertex] -> [Point]transList [] = []transList (p:ps) = trans p : transList ps

(xWin2,yWin2)

(xWin,yWin)

Page 6: 深入浅出 Haskell

从 Shape 到 GraphicshapeToGraphic :: Shape -> GraphicshapeToGraphic (Rectangle s1 s2) = let s12 = s1/2 s22 = s2/2 in polygon (transList [(-s12,-s22),(-s12,s22), (s12,s22), (s12,-s22)])shapeToGraphic (Ellipse r1 r2) = ellipse (trans (-r1,-r2)) (trans (r1,r2)) shapeToGraphic (RtTriangle s1 s2) = polygon (transList [(0,0),(s1,0),(0,s2)])shapeToGraphic (Polygon pts) = polygon (transList pts)

Page 7: 深入浅出 Haskell

一些形状sh1,sh2,sh3,sh4 :: Shape

sh1 = Rectangle 3 2sh2 = Ellipse 1 1.5sh3 = RtTriangle 3 2sh4 = Polygon [(-2.5,2.5), (-1.5,2.0), (-1.1,0.2), (-1.7,-1.0), (-3.0,0)]

Page 8: 深入浅出 Haskell

画出来main10 = runGraphics $ do w <- openWindow "Drawing Shapes" (xWin,yWin) drawInWindow w (withColor Red (shapeToGraphic sh1)) drawInWindow w (withColor Blue (shapeToGraphic sh2)) spaceClose w

Page 9: 深入浅出 Haskell

结果

Page 10: 深入浅出 Haskell

Shape列表的绘制type ColoredShapes = [(Color,Shape)]

shs :: ColoredShapesshs = [(Red,sh1),(Blue,sh2), (Yellow,sh3),(Magenta,sh4)] drawShapes :: Window -> ColoredShapes -> IO ()drawShapes w [] = return ()drawShapes w ((c,s):cs) = do drawInWindow w (withColor c (shapeToGraphic s)) drawShapes w csmain11 = runGraphics $ do w <- openWindow "Drawing Shapes" (xWin,yWin) drawShapes w shs spaceClose w

Page 11: 深入浅出 Haskell

结果

Page 12: 深入浅出 Haskell

Polymorphism• 允许我们用统一的方式处理一组类型• 多态数据类型是多态化的根源,操作多态数据的函数也随之具备了多

态性• Haskell 的这种多态又被称为参数化多态 (Parametric polymorphism)

,在 Java , C++ 中称为泛型 (Generic)

Page 13: 深入浅出 Haskell

高阶函数• 参数是函数

• 或者返回值是函数

• 函数也可以放在数据结构里

Page 14: 深入浅出 Haskell

Polymorphic Length

length :: [a] -> Intlength [] = 0length (x:xs) = 1 + length xs

-- 多态函数不会去窥视多态化参数,也不关心这个类型具体是什么length [1,2,3] -- 3length [’a’,’b’,’c’] -- 3length [[2],[],[1,2,3]] -- 3

a 是一个类型参数,将其小写以区别首字母大写的类型名

Page 15: 深入浅出 Haskell

多态数据结构• 如果数据结构不关心其内部数据的类型,便可让多态性派

上用场

• 典型的多态数据结构有:

List: [a]Tuple: (a,b)

• 当然也可以自定义新的多态数据类型

Page 16: 深入浅出 Haskell

Maybe maybe useful -- 类型参数 a 使得 Maybe 具有了多态性 data Maybe a = Nothing | Just a

-- 注意构造器的类型 Nothing :: Maybe aJust :: a -> Maybe a

Just 3 :: Maybe IntJust "x" :: Maybe StringJust (3,True) :: Maybe (Int,Bool)Just (Just 1) :: Maybe (Maybe Int)safeDivide :: Int -> Int -> Maybe IntsafeDivide x 0 = NothingsafeDivide x y = Just (x/y)

Page 17: 深入浅出 Haskell

某种递归的模式transList :: [Vertex] -> [Point]transList [] = []transList (p:ps) = trans p : transList ps

putCharList :: [Char] -> [IO ()]putCharList [] = []putCharList (c:cs) = putChar c : putCharList cs

Page 18: 深入浅出 Haskell

公共模式的抽象• 上述模式中只有 trans和 putChar 是不同的

• 试着把它们提取出来作为一个抽象函数的参数

-- 把这个抽象函数命名为 mapmap f [] = []map f (x:xs) = f x : map f xs

-- 用 map 重新定义 transList和 putCharListtransList xs = map trans xsputCharList cs = map putChar cs

Page 19: 深入浅出 Haskell

多态的高阶的map-- map 是个多态函数,并且是个高阶函数-- 不管 a 具体是什么类型,所有位置的 a-- 必须对应相同的类型, b 也是这样map :: (a->b) -> [a] -> [b]

trans :: Vertex -> Pointmap trans :: [Vertex] -> [Point]

putChar :: Char -> IO ()map putChar :: [Char] -> [IO ()]

Page 20: 深入浅出 Haskell

Arithmetic Sequences• 构建符合一定规律的 List

[1 .. 6] = [1,2,3,4,5,6][1,3 .. 9] = [1,3,5,7,9][5,4 .. 1] = [5,4,3,2,1]

• [a, b..c] 称作 arithmetic sequence, 实际是 [a, a + d, a + 2 * d, ..., c] 的简写,其中 d = b - a

• 无穷列表 take 9 [1,3..] = [1,3,5,7,9,11,13,15,17] take 5 [5..] = [5,6,7,8,9]

Page 21: 深入浅出 Haskell

同心圆conCircles = map circle [2.4, 2.1 .. 0.3]

coloredCircles = zip [Black,Blue,Green,Cyan,Red,Magenta,Yellow,White] conCircles

main = runGraphics $ do w <- openWindow "Drawing Shapes" (xWin,yWin) drawShapes w (reverse coloredCircles) spaceClose w

Page 22: 深入浅出 Haskell

结果

Page 23: 深入浅出 Haskell

• 满足结合率(xs ++ ys) ++ zs == xs ++ (ys ++ zs)

• Prelude对 (++) fixity 的定义: infixr 5 ++ ,所以

xs ++ ys ++ zs xs ++ (ys ++ zs)

Append List(++) :: [a] -> [a] -> [a][] ++ ys == ys(x:xs) ++ ys == x : (xs ++ ys)

"hello" ++ " world" -- "hello world"[1,2,3] ++ [4,5,6] -- [1,2,3,4,5,6]-- 上式按照定义展开得到 1:(2:(3:([]++[4,5,6])))

时间复杂度和第一个参数的长度成正比

length xs + length ys

length xs + (length xs + length ys)

Page 24: 深入浅出 Haskell

另一种递归的模式listSum [] = 0listSum (x:xs) = x + listSum xs

listProd [] = 1listProd (x:xs) = x * listProd xs

Page 25: 深入浅出 Haskell

fold-- 注意 fold也是多态的,当然也是高阶的fold :: (a -> b -> b) -> b -> [a] -> b

-- 再一次地把重复的模式抽象出来,成为:fold op init [] = initfold op init (x:xs) = x `op` fold op init xs

-- 尝尝 foldlistSum xs = fold (+) 0 xslistProd xs = fold (*) 1 xs

Page 26: 深入浅出 Haskell

两种 fold• fold 在 Haskell 里已经预定义了,只不过名字是叫 foldr, 因为它

是从右开始折叠的 :

foldr op init (x1 : x2 : ... : xn : []) x1 `op` (x2 `op` (...(xn `op` init)...))

• 还有一个 foldl ,是从左开始折叠 :

foldl op init (x1 : x2 : ... : xn : []) (...((init `op` x1) `op` x2)...) `op` xn

• 为什么要有两个 fold ?因为有时候其中一个会比另一个更有效率: foldr (++) [] [x,y,z] x ++ (y ++ z) foldl (++) [] [x,y,z] (x ++ y) ++ z

上述两个计算,前者要比后者更有效率,另外的情况下可能是 foldl更有效率 !

Page 27: 深入浅出 Haskell

Reverse List• 最简单的实现,不过效率呢?

reverse [] = []

reverse (x::xs) = reverse xs ++ [x]

• 改进一下,好了一点吗? reverse xs = rev [] xs

where rev acc [] = acc

rev acc (x:xs) = rev (x:acc) xs

• 看起来象 foldl ,再改进一下: reverse xs = foldl revOp [] xs

where revOp a b = b : a

Page 28: 深入浅出 Haskell

有没有问题?有没有问题?

Page 29: 深入浅出 Haskell

作业• 在屏幕上画些 Shape

• 再画些有趣的分形

Page 30: 深入浅出 Haskell

关于作者@邓际锋 , 网易杭研院程序员

个人研究兴趣 编程语言的设计与实现 交互式艺术及 FP在该领域的应用 如何为儿童和非技术人员开发富有乐趣的创作工具

http://weibo.com/ideamonad

[email protected]

http://blog.csdn.net/soloist