Last active
May 10, 2017 15:37
-
-
Save en-em/1d21e701bd0f50d4ba6a30e30f9351f3 to your computer and use it in GitHub Desktop.
Haskell shape GADTs typeclasses vs direct vtaables
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE GADTs #-} | |
type Point = (Double, Double) | |
type Vector = (Double, Double) | |
type Angle = Double | |
type Mat23 = (Vector, Vector, Vector) | |
(+%+ ) :: Point -> Vector -> Point | |
(x,y) +%+ (u,v) = (x+u, y+v) | |
(-%-) :: Point -> Vector -> Point | |
(x,y) -%- (u,v) = (x-u, y-v) | |
(*%*) :: Point -> Double -> Point | |
(x, y) *%* z = (x*z, y*z) | |
rotPoint center theta p = rp +%+ center where | |
rp = (rx, ry) | |
(rx, ry) = (tx * cos theta - ty * sin theta, tx * sin theta + ty * cos theta) | |
(tx, ty) = p -%- center | |
scPoint center factor p = (p -%- center) *%* factor +%+ center | |
data ShapeVtable a = ShapeVtable { | |
v_draw :: a -> IO (), | |
v_translate :: Vector -> a -> a, | |
v_rotate :: Point -> Angle -> a -> a, | |
v_scale :: Point -> Double -> a -> a | |
} | |
data Shape where | |
Shape :: a -> ShapeVtable a -> Shape | |
draw :: Shape -> IO () | |
draw (Shape self vtbl) = (v_draw vtbl) self | |
translate :: Vector -> Shape -> Shape | |
translate offset (Shape self vtbl) = Shape ((v_translate vtbl) offset self) vtbl | |
rotate :: Point -> Double -> Shape -> Shape | |
rotate center angle (Shape self vtbl) = Shape ((v_rotate vtbl) center angle self) vtbl | |
scale :: Point -> Double -> Shape -> Shape | |
scale center factor (Shape self vtbl) = Shape ((v_rotate vtbl) center factor self) vtbl | |
data Triangle = Triangle Point Point Point deriving Show | |
data Circle = Circle Point Double deriving Show | |
triangleVtable :: ShapeVtable Triangle | |
triangleVtable = ShapeVtable drawTriangle translateTriangle rotateTriangle scaleTriangle | |
circleVtable :: ShapeVtable Circle | |
circleVtable = ShapeVtable drawCircle translateCircle rotateCircle scaleCircle | |
drawTriangle :: Triangle -> IO () | |
drawTriangle tri = print tri | |
translateTriangle offset (Triangle a b c) = Triangle (a +%+ offset) (b +%+ offset) (c +%+ offset) | |
rotateTriangle center theta (Triangle a b c) = Triangle (rotPoint center theta a) (rotPoint center theta b) (rotPoint center theta c) | |
scaleTriangle center factor (Triangle a b c) = Triangle (scPoint center factor a) (scPoint center factor b) (scPoint center factor c) | |
drawCircle :: Circle -> IO () | |
drawCircle crc = print crc | |
translateCircle offset (Circle c r) = Circle (c +%+ offset) r | |
rotateCircle center theta (Circle c r) = Circle (rotPoint center theta c) r | |
scaleCircle center factor (Circle c r) = Circle (scPoint center factor c) r | |
myShapes = [Shape (Circle (3,4) 7) circleVtable, Shape (Triangle (0,0) (3,0) (0,4)) triangleVtable] | |
main = do | |
let transformedShapes = map (translate (2,5) . rotate (4,4) (pi/4) . scale (-2, 0) 0.5) myShapes | |
sequence_ $ map draw myShapes | |
sequence_ $ map draw transformedShapes |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE GADTs #-} | |
type Point = (Double, Double) | |
type Vector = (Double, Double) | |
type Angle = Double | |
type Mat23 = (Vector, Vector, Vector) | |
(+%+ ) :: Point -> Vector -> Point | |
(x,y) +%+ (u,v) = (x+u, y+v) | |
(-%-) :: Point -> Vector -> Point | |
(x,y) -%- (u,v) = (x-u, y-v) | |
(*%*) :: Point -> Double -> Point | |
(x, y) *%* z = (x*z, y*z) | |
rotPoint center theta p = rp +%+ center where | |
rp = (rx, ry) | |
(rx, ry) = (tx * cos theta - ty * sin theta, tx * sin theta + ty * cos theta) | |
(tx, ty) = p -%- center | |
scPoint center factor p = (p -%- center) *%* factor +%+ center | |
class CShape a where | |
draw :: a -> IO () | |
translate :: Vector -> a -> a | |
rotate :: Point -> Angle -> a -> a | |
scale :: Point -> Double -> a -> a | |
data Shape where | |
Shape :: (CShape a) => a -> Shape | |
instance CShape Shape where | |
draw (Shape a) = draw a | |
translate offset (Shape a) = Shape (translate offset a) | |
rotate center theta (Shape a) = Shape (rotate center theta a) | |
scale center factor (Shape a) = Shape (scale center factor a) | |
data Triangle = Triangle Point Point Point deriving Show | |
data Circle = Circle Point Double deriving Show | |
instance CShape Triangle where | |
draw = print | |
translate offset (Triangle a b c) = Triangle (a +%+ offset) (b +%+ offset) (c +%+ offset) | |
rotate center theta (Triangle a b c) = Triangle (rotPoint center theta a) (rotPoint center theta b) (rotPoint center theta c) | |
scale center factor (Triangle a b c) = Triangle (scPoint center factor a) (scPoint center factor b) (scPoint center factor c) | |
instance CShape Circle where | |
draw = print | |
translate offset (Circle c r) = Circle (c +%+ offset) r | |
rotate center theta (Circle c r) = Circle (rotPoint center theta c) r | |
scale center factor (Circle c r) = Circle (scPoint center factor c) r | |
myShapes = [Shape (Circle (3,4) 7), Shape (Triangle (0,0) (3,0) (0,4))] | |
main = do | |
let transformedShapes = map (translate (2,5) . rotate (4,4) (pi/4) . scale (-2, 0) 0.5) myShapes | |
sequence_ $ map draw myShapes | |
sequence_ $ map draw transformedShapes |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment