numhask-space-0.2.0: src/NumHask/Point.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wall #-}
-- | A 2-dimensional point.
module NumHask.Point
( Point(..)
, pattern Point
, rotate
, gridP
) where
import Prelude
import GHC.Generics (Generic)
import Data.Functor.Classes
import Text.Show
import Algebra.Lattice
import Data.Functor.Rep
import Data.Distributive as D
import NumHask.Range
import NumHask.Space.Types
-- $setup
-- >>> :set -XNoImplicitPrelude
-- >>> :set -XFlexibleContexts
--
-- | A 2-dim point of a's, implemented as a tuple, but api represented as Point a a.
--
-- >>> fmap (+1) (Point 1 2)
-- Point 2 3
-- >>> pure one :: Point Int
-- Point 1 1
-- >>> (*) <$> Point 1 2 <*> pure 2
-- Point 2 4
-- >>> foldr (++) [] (Point [1,2] [3])
-- [1,2,3]
-- >>> Point "a" "pair" `mappend` pure " " `mappend` Point "string" "mappended"
-- Point "a string" "pair mappended"
--
-- As a Ring and Field class
--
-- >>> Point 0 1 + zero
-- Point 0 1
-- >>> Point 0 1 + Point 2 3
-- Point 2 4
-- >>> Point 1 1 - one
-- Point 0 0
-- >>> Point 0 1 * one
-- Point 0 1
-- >>> Point 0.0 1.0 / one
-- Point 0.0 1.0
-- >>> Point 11 12 `mod` (pure 6)
-- Point 5 0
newtype Point a =
Point' (a, a)
deriving (Eq, Generic)
-- | the preferred pattern
pattern Point :: a -> a -> Point a
pattern Point a b = Point' (a,b)
{-# COMPLETE Point#-}
instance (Show a) => Show (Point a) where
show (Point a b) = "Point " <> Text.Show.show a <> " " <> Text.Show.show b
instance Functor Point where
fmap f (Point a b) = Point (f a) (f b)
instance Eq1 Point where
liftEq f (Point a b) (Point c d) = f a c && f b d
instance Show1 Point where
liftShowsPrec sp _ d (Point' (a, b)) = showsBinaryWith sp sp "Point" d a b
instance Applicative Point where
pure a = Point a a
(Point fa fb) <*> Point a b = Point (fa a) (fb b)
instance Monad Point where
Point a b >>= f = Point a' b'
where
Point a' _ = f a
Point _ b' = f b
instance Foldable Point where
foldMap f (Point a b) = f a `mappend` f b
instance Traversable Point where
traverse f (Point a b) = Point <$> f a <*> f b
instance (Semigroup a) => Semigroup (Point a) where
(Point a0 b0) <> (Point a1 b1) = Point (a0 <> a1) (b0 <> b1)
instance (Semigroup a, Monoid a) => Monoid (Point a) where
mempty = Point mempty mempty
mappend = (<>)
instance (Bounded a) => Bounded (Point a) where
minBound = Point minBound minBound
maxBound = Point maxBound maxBound
unaryOp :: (a -> a) -> (Point a -> Point a)
unaryOp f (Point a b) = Point (f a) (f b)
instance (Num a) => Num (Point a) where
(Point a0 b0) + (Point a1 b1) = Point (a0 + a1) (b0 + b1)
negate = unaryOp negate
(Point a0 b0) * (Point a1 b1) = Point (a0 * a1) (b0 * b1)
signum = unaryOp signum
abs = unaryOp abs
fromInteger x = Point (fromInteger x) (fromInteger x)
instance (Fractional a) => Fractional (Point a) where
fromRational x = Point (fromRational x) 0
recip = unaryOp recip
instance Distributive Point where
collect f x = Point (getL . f <$> x) (getR . f <$> x)
where getL (Point l _) = l
getR (Point _ r) = r
instance Representable Point where
type Rep Point = Bool
tabulate f = Point (f False) (f True)
index (Point l _) False = l
index (Point _ r) True = r
instance (Ord a) => Lattice (Point a) where
(\/) (Point x y) (Point x' y') = Point (max x x') (max y y')
(/\) (Point x y) (Point x' y') = Point (min x x') (min y y')
-- | rotate a point by x degrees relative to the origin
rotate :: (Floating a) => a -> Point a -> Point a
rotate d (Point x y) = Point (x * cos d' + y*sin d') (y* cos d'-x*sin d')
where
d' = d*pi/180
-- | Create Points for a formulae y = f(x) across an x range
gridP :: (Ord a, Fractional a) => (a -> a) -> Range a -> Int -> [Point a]
gridP f r g = (\x -> Point x (f x)) <$> grid OuterPos r g