{-# LANGUAGE GADTs #-} -- only for presentation module Shape.Deep ( -- * Types Shape -- abstract -- * Constructor functions , empty, circle, square -- * Primitive combinators , transform, translate , union, intersect, invert -- * Run functions , inside ) where import Matrix -- | In a deep embedding our objects are represented by a datatype -- with constructors for each primitive operation. {- From the lecture slides: type Shape -- Constructor functions empty :: Shape circle :: Shape square :: Shape -- Combinators translate :: Vec -> Shape -> Shape scale :: Vec -> Shape -> Shape rotate :: Angle -> Shape -> Shape union :: Shape -> Shape -> Shape intersect :: Shape -> Shape -> Shape difference:: Shape -> Shape -> Shape Later scale, rotate, difference are derived from invert and transform: invert :: Shape -> Shape transform :: Matrix -> Shape -> Shape -} data Shape where -- Constructor functions Empty :: Shape Circle :: Shape Square :: Shape -- Combinators Translate :: Vec -> Shape -> Shape Transform :: Matrix-> Shape -> Shape Union :: Shape -> Shape -> Shape Intersect :: Shape -> Shape -> Shape Invert :: Shape -> Shape {- -- Shape without GADT syntax data Shape = Empty | Circle | Square | Translate Vec Shape | Transform Matrix Shape | Union Shape Shape | Intersect Shape Shape | Invert Shape -} -- Creation functions empty :: Shape empty = Empty circle :: Shape circle = Circle square :: Shape square = Square -- Primitive combinators transform :: Matrix -> Shape -> Shape transform = Transform translate :: Vec -> Shape -> Shape translate = Translate union :: Shape -> Shape -> Shape union = Union intersect :: Shape -> Shape -> Shape intersect = Intersect invert :: Shape -> Shape invert = Invert -- Run functions inside :: Point -> Shape -> Bool _p `inside` Empty = False p `inside` Circle = distance p <= 1 p `inside` Square = maxnorm p <= 1 p `inside` Translate v sh = (p `sub` v) `inside` sh p `inside` Transform m sh = (inv m `mul` p) `inside` sh p `inside` Union sh1 sh2 = p `inside` sh1 || p `inside` sh2 p `inside` Intersect sh1 sh2 = p `inside` sh1 && p `inside` sh2 p `inside` Invert sh = not (p `inside` sh) distance :: Point -> Double distance p = x*x+y*y -- proper distance would use sqrt where x = ptX p y = ptY p maxnorm :: Point -> Double maxnorm p = max (abs x) (abs y) where x = ptX p y = ptY p -- http://en.wikipedia.org/wiki/Norm_%28mathematics%29#Properties