Skip to content

Instantly share code, notes, and snippets.

@en-em
Last active May 10, 2017 15:37
Show Gist options
  • Save en-em/1d21e701bd0f50d4ba6a30e30f9351f3 to your computer and use it in GitHub Desktop.
Save en-em/1d21e701bd0f50d4ba6a30e30f9351f3 to your computer and use it in GitHub Desktop.
Haskell shape GADTs typeclasses vs direct vtaables
{-# 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
{-# 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