-- |
-- Module      : Data.Express.Name
-- Copyright   : (c) 2019-2021 Rudy Matela
-- License     : 3-Clause BSD  (see the file LICENSE)
-- Maintainer  : Rudy Matela <rudy@matela.com.br>
--
-- Defines the 'Name' type class.
module Data.Express.Name
  ( Name (..)
  , names
  , variableNamesFromTemplate
  )
where

import Data.Express.Utils.String

import Data.Char
import Data.List
import Data.Ratio (Ratio)
import Data.Word (Word) -- for GHC <= 7.8

-- |
-- If we were to come up with a variable name for the given type
-- what 'name' would it be?
--
-- An instance for a given type @ Ty @ is simply given by:
--
-- > instance Name Ty where name _ = "x"
--
-- Examples:
--
-- > > name (undefined :: Int)
-- > "x"
--
-- > > name (undefined :: Bool)
-- > "p"
--
-- > > name (undefined :: [Int])
-- > "xs"
--
-- This is then used to generate an infinite list of variable 'names':
--
-- > > names (undefined :: Int)
-- > ["x", "y", "z", "x'", "y'", "z'", "x''", "y''", "z''", ...]
--
-- > > names (undefined :: Bool)
-- > ["p", "q", "r", "p'", "q'", "r'", "p''", "q''", "r''", ...]
--
-- > > names (undefined :: [Int])
-- > ["xs", "ys", "zs", "xs'", "ys'", "zs'", "xs''", "ys''", ...]
class Name a where
  -- | /O(1)./
  --
  -- Returns a name for a variable of the given argument's type.
  --
  -- > > name (undefined :: Int)
  -- > "x"
  --
  -- > > name (undefined :: [Bool])
  -- > "ps"
  --
  -- > > name (undefined :: [Maybe Integer])
  -- > "mxs"
  --
  -- The default definition is:
  --
  -- > name _ = "x"
  name :: a -> String
  name a
_ = String
"x"

-- |
-- > name (undefined :: ()) = "u"
-- > names (undefined :: ()) = ["u", "v", "w", "u'", "v'", ...]
instance Name ()        where  name :: () -> String
name ()
_  =  String
"u"

-- |
-- > name (undefined :: Bool) = "p"
-- > names (undefined :: Bool) = ["p", "q", "r", "p'", "q'", ...]
instance Name Bool      where  name :: Bool -> String
name Bool
_  =  String
"p"

-- |
-- > name (undefined :: Int) = "x"
-- > names (undefined :: Int) = ["x", "y", "z", "x'", "y'", ...]
instance Name Int       where  name :: Int -> String
name Int
_  =  String
"x"

-- |
-- > name (undefined :: Integer) = "x"
-- > names (undefined :: Integer) = ["x", "y", "z", "x'", ...]
instance Name Integer   where  name :: Integer -> String
name Integer
_  =  String
"x"

-- |
-- > name (undefined :: Char) = "c"
-- > names (undefined :: Char) = ["c", "d", "e", "c'", "d'", ...]
instance Name Char      where  name :: Char -> String
name Char
_  =  String
"c"

-- |
-- > name (undefined :: Ordering) = "o"
-- > names (undefined :: Ordering) = ["o", "p", "q", "o'", ...]
instance Name Ordering  where  name :: Ordering -> String
name Ordering
_  =  String
"o"

-- |
-- > name (undefined :: Rational) = "q"
-- > names (undefined :: Rational) = ["q", "r", "s", "q'", ...]
instance Name (Ratio a) where  name :: Ratio a -> String
name Ratio a
_  =  String
"q"

-- |
-- > name (undefined :: Float) = "x"
-- > names (undefined :: Float) = ["x", "y", "z", "x'", ...]
instance Name Float     where  name :: Float -> String
name Float
_  =  String
"x"

-- |
-- > name (undefined :: Double) = "x"
-- > names (undefined :: Double) = ["x", "y", "z", "x'", ...]
instance Name Double    where  name :: Double -> String
name Double
_  =  String
"x"

-- |
-- > names (undefined :: ()->()) = ["f", "g", "h", "f'", ...]
-- > names (undefined :: Int->Int) = ["f", "g", "h", ...]
instance Name (a -> b)  where  name :: (a -> b) -> String
name a -> b
_  =  String
"f"

-- |
-- > names (undefined :: Maybe Int) = ["mx", "mx1", "mx2", ...]
-- > nemes (undefined :: Maybe Bool) = ["mp", "mp1", "mp2", ...]
instance Name a => Name (Maybe a) where
  name :: Maybe a -> String
name Maybe a
mx  =  String
"m" String -> String -> String
forall a. [a] -> [a] -> [a]
++ a -> String
forall a. Name a => a -> String
name a
x
    where
    Just a
x = Maybe a
mx

-- |
-- > names (undefined :: Either Int Int) = ["exy", "exy1", ...]
-- > names (undefined :: Either Int Bool) = ["exp", "exp1", ...]
instance (Name a, Name b) => Name (Either a b) where
  name :: Either a b -> String
name Either a b
exy  =  String
"e" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
n String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
m
    where
    Left a
x  = Either a b
exy
    Right b
y = Either a b
exy
    n :: String
n = a -> String
forall a. Name a => a -> String
name a
x
    m :: String
m = [String] -> String
forall a. [a] -> a
head ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ b -> [String]
forall a. Name a => a -> [String]
names b
y [String] -> [String] -> [String]
forall a. Eq a => [a] -> [a] -> [a]
\\ [String
n]

-- |
-- > names (undefined :: (Int,Int)) = ["xy", "zw", "xy'", ...]
-- > names (undefined :: (Bool,Bool)) = ["pq", "rs", "pq'", ...]
instance (Name a, Name b) => Name (a,b) where
  name :: (a, b) -> String
name (a, b)
xy  =  String
n String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
m
    where
    (a
x,b
y)  =  (a, b)
xy
    n :: String
n  =  a -> String
forall a. Name a => a -> String
name a
x
    m :: String
m  =  [String] -> String
forall a. [a] -> a
head ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ b -> [String]
forall a. Name a => a -> [String]
names b
y [String] -> [String] -> [String]
forall a. Eq a => [a] -> [a] -> [a]
\\ [String
n]

-- |
-- > names (undefined :: (Int,Int,Int)) = ["xyz","uvw", ...]
-- > names (undefined :: (Int,Bool,Char)) = ["xpc", "xpc1", ...]
instance (Name a, Name b, Name c) => Name (a,b,c) where
  name :: (a, b, c) -> String
name (a, b, c)
xyz  =  String
n String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
m String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
o
    where
    (a
x,b
y,c
z)  =  (a, b, c)
xyz
    n :: String
n  =  a -> String
forall a. Name a => a -> String
name a
x
    m :: String
m  =  [String] -> String
forall a. [a] -> a
head ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ b -> [String]
forall a. Name a => a -> [String]
names b
y [String] -> [String] -> [String]
forall a. Eq a => [a] -> [a] -> [a]
\\ [String
n]
    o :: String
o  =  [String] -> String
forall a. [a] -> a
head ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ c -> [String]
forall a. Name a => a -> [String]
names c
z [String] -> [String] -> [String]
forall a. Eq a => [a] -> [a] -> [a]
\\ [String
n,String
m]

-- |
-- > names (undefined :: ((),(),(),())) = ["uuuu", "uuuu1", ...]
-- > names (undefined :: (Int,Int,Int,Int)) = ["xxxx", ...]
instance (Name a, Name b, Name c, Name d) => Name (a,b,c,d) where
  name :: (a, b, c, d) -> String
name (a, b, c, d)
xyzw  =  a -> String
forall a. Name a => a -> String
name a
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ b -> String
forall a. Name a => a -> String
name b
y String -> String -> String
forall a. [a] -> [a] -> [a]
++ c -> String
forall a. Name a => a -> String
name c
z String -> String -> String
forall a. [a] -> [a] -> [a]
++ d -> String
forall a. Name a => a -> String
name d
w  where  (a
x,b
y,c
z,d
w)  =  (a, b, c, d)
xyzw

-- |
-- > names (undefined :: [Int]) = ["xs", "ys", "zs", "xs'", ...]
-- > names (undefined :: [Bool]) = ["ps", "qs", "rs", "ps'", ...]
instance Name a => Name [a] where
  name :: [a] -> String
name [a]
xs  =  a -> String
forall a. Name a => a -> String
name ([a] -> a
forall a. [a] -> a
head [a]
xs) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"s"

-- |
-- Returns na infinite list of variable names from the given type:
-- the result of 'variableNamesFromTemplate' after 'name'.
--
-- > > names (undefined :: Int)
-- > ["x", "y", "z", "x'", "y'", "z'", "x''", "y''", "z''", ...]
--
-- > > names (undefined :: Bool)
-- > ["p", "q", "r", "p'", "q'", "r'", "p''", "q''", "r''", ...]
--
-- > > names (undefined :: [Int])
-- > ["xs", "ys", "zs", "xs'", "ys'", "zs'", "xs''", "ys''", ...]
names :: Name a => a -> [String]
names :: a -> [String]
names  =  String -> [String]
variableNamesFromTemplate (String -> [String]) -> (a -> String) -> a -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. Name a => a -> String
name


-- instances of further types and arities --

instance Name Word where  name :: Word -> String
name Word
_  =  String
"x"

instance (Name a, Name b, Name c, Name d, Name e) => Name (a,b,c,d,e) where
  name :: (a, b, c, d, e) -> String
name (a, b, c, d, e)
xyzwv  =  a -> String
forall a. Name a => a -> String
name a
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ b -> String
forall a. Name a => a -> String
name b
y String -> String -> String
forall a. [a] -> [a] -> [a]
++ c -> String
forall a. Name a => a -> String
name c
z String -> String -> String
forall a. [a] -> [a] -> [a]
++ d -> String
forall a. Name a => a -> String
name d
w String -> String -> String
forall a. [a] -> [a] -> [a]
++ e -> String
forall a. Name a => a -> String
name e
v
    where  (a
x,b
y,c
z,d
w,e
v)  =  (a, b, c, d, e)
xyzwv

instance (Name a, Name b, Name c, Name d, Name e, Name f)
      => Name (a,b,c,d,e,f) where
  name :: (a, b, c, d, e, f) -> String
name (a, b, c, d, e, f)
xyzwvu  =  a -> String
forall a. Name a => a -> String
name a
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ b -> String
forall a. Name a => a -> String
name b
y String -> String -> String
forall a. [a] -> [a] -> [a]
++ c -> String
forall a. Name a => a -> String
name c
z String -> String -> String
forall a. [a] -> [a] -> [a]
++ d -> String
forall a. Name a => a -> String
name d
w String -> String -> String
forall a. [a] -> [a] -> [a]
++ e -> String
forall a. Name a => a -> String
name e
v String -> String -> String
forall a. [a] -> [a] -> [a]
++ f -> String
forall a. Name a => a -> String
name f
u
    where  (a
x,b
y,c
z,d
w,e
v,f
u)  =  (a, b, c, d, e, f)
xyzwvu

instance (Name a, Name b, Name c, Name d, Name e, Name f, Name g)
      => Name (a,b,c,d,e,f,g) where
  name :: (a, b, c, d, e, f, g) -> String
name (a, b, c, d, e, f, g)
xyzwvut  =  a -> String
forall a. Name a => a -> String
name a
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ b -> String
forall a. Name a => a -> String
name b
y String -> String -> String
forall a. [a] -> [a] -> [a]
++ c -> String
forall a. Name a => a -> String
name c
z String -> String -> String
forall a. [a] -> [a] -> [a]
++ d -> String
forall a. Name a => a -> String
name d
w
                String -> String -> String
forall a. [a] -> [a] -> [a]
++ e -> String
forall a. Name a => a -> String
name e
v String -> String -> String
forall a. [a] -> [a] -> [a]
++ f -> String
forall a. Name a => a -> String
name f
u String -> String -> String
forall a. [a] -> [a] -> [a]
++ g -> String
forall a. Name a => a -> String
name g
t
    where  (a
x,b
y,c
z,d
w,e
v,f
u,g
t)  =  (a, b, c, d, e, f, g)
xyzwvut

instance (Name a, Name b, Name c, Name d, Name e, Name f, Name g, Name h)
      => Name (a,b,c,d,e,f,g,h) where
  name :: (a, b, c, d, e, f, g, h) -> String
name (a, b, c, d, e, f, g, h)
xyzwvuts  =  a -> String
forall a. Name a => a -> String
name a
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ b -> String
forall a. Name a => a -> String
name b
y String -> String -> String
forall a. [a] -> [a] -> [a]
++ c -> String
forall a. Name a => a -> String
name c
z String -> String -> String
forall a. [a] -> [a] -> [a]
++ d -> String
forall a. Name a => a -> String
name d
w
                 String -> String -> String
forall a. [a] -> [a] -> [a]
++ e -> String
forall a. Name a => a -> String
name e
v String -> String -> String
forall a. [a] -> [a] -> [a]
++ f -> String
forall a. Name a => a -> String
name f
u String -> String -> String
forall a. [a] -> [a] -> [a]
++ g -> String
forall a. Name a => a -> String
name g
t String -> String -> String
forall a. [a] -> [a] -> [a]
++ h -> String
forall a. Name a => a -> String
name h
s
    where  (a
x,b
y,c
z,d
w,e
v,f
u,g
t,h
s)  =  (a, b, c, d, e, f, g, h)
xyzwvuts

instance ( Name a, Name b, Name c, Name d
         , Name e, Name f, Name g, Name h
         , Name i)
      => Name (a,b,c,d,e,f,g,h,i) where
  name :: (a, b, c, d, e, f, g, h, i) -> String
name (a, b, c, d, e, f, g, h, i)
xyzwvutsr  =  a -> String
forall a. Name a => a -> String
name a
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ b -> String
forall a. Name a => a -> String
name b
y String -> String -> String
forall a. [a] -> [a] -> [a]
++ c -> String
forall a. Name a => a -> String
name c
z String -> String -> String
forall a. [a] -> [a] -> [a]
++ d -> String
forall a. Name a => a -> String
name d
w
                  String -> String -> String
forall a. [a] -> [a] -> [a]
++ e -> String
forall a. Name a => a -> String
name e
v String -> String -> String
forall a. [a] -> [a] -> [a]
++ f -> String
forall a. Name a => a -> String
name f
u String -> String -> String
forall a. [a] -> [a] -> [a]
++ g -> String
forall a. Name a => a -> String
name g
t String -> String -> String
forall a. [a] -> [a] -> [a]
++ h -> String
forall a. Name a => a -> String
name h
s
                  String -> String -> String
forall a. [a] -> [a] -> [a]
++ i -> String
forall a. Name a => a -> String
name i
r
    where  (a
x,b
y,c
z,d
w,e
v,f
u,g
t,h
s,i
r)  =  (a, b, c, d, e, f, g, h, i)
xyzwvutsr

instance ( Name a, Name b, Name c, Name d
         , Name e, Name f, Name g, Name h
         , Name i, Name j )
      => Name (a,b,c,d,e,f,g,h,i,j) where
  name :: (a, b, c, d, e, f, g, h, i, j) -> String
name (a, b, c, d, e, f, g, h, i, j)
xyzwvutsrq  =  a -> String
forall a. Name a => a -> String
name a
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ b -> String
forall a. Name a => a -> String
name b
y String -> String -> String
forall a. [a] -> [a] -> [a]
++ c -> String
forall a. Name a => a -> String
name c
z String -> String -> String
forall a. [a] -> [a] -> [a]
++ d -> String
forall a. Name a => a -> String
name d
w
                   String -> String -> String
forall a. [a] -> [a] -> [a]
++ e -> String
forall a. Name a => a -> String
name e
v String -> String -> String
forall a. [a] -> [a] -> [a]
++ f -> String
forall a. Name a => a -> String
name f
u String -> String -> String
forall a. [a] -> [a] -> [a]
++ g -> String
forall a. Name a => a -> String
name g
t String -> String -> String
forall a. [a] -> [a] -> [a]
++ h -> String
forall a. Name a => a -> String
name h
s
                   String -> String -> String
forall a. [a] -> [a] -> [a]
++ i -> String
forall a. Name a => a -> String
name i
r String -> String -> String
forall a. [a] -> [a] -> [a]
++ j -> String
forall a. Name a => a -> String
name j
q
    where  (a
x,b
y,c
z,d
w,e
v,f
u,g
t,h
s,i
r,j
q)  =  (a, b, c, d, e, f, g, h, i, j)
xyzwvutsrq

instance ( Name a, Name b, Name c, Name d
         , Name e, Name f, Name g, Name h
         , Name i, Name j, Name k )
      => Name (a,b,c,d,e,f,g,h,i,j,k) where
  name :: (a, b, c, d, e, f, g, h, i, j, k) -> String
name (a, b, c, d, e, f, g, h, i, j, k)
xyzwvutsrqp  =  a -> String
forall a. Name a => a -> String
name a
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ b -> String
forall a. Name a => a -> String
name b
y String -> String -> String
forall a. [a] -> [a] -> [a]
++ c -> String
forall a. Name a => a -> String
name c
z String -> String -> String
forall a. [a] -> [a] -> [a]
++ d -> String
forall a. Name a => a -> String
name d
w
                    String -> String -> String
forall a. [a] -> [a] -> [a]
++ e -> String
forall a. Name a => a -> String
name e
v String -> String -> String
forall a. [a] -> [a] -> [a]
++ f -> String
forall a. Name a => a -> String
name f
u String -> String -> String
forall a. [a] -> [a] -> [a]
++ g -> String
forall a. Name a => a -> String
name g
t String -> String -> String
forall a. [a] -> [a] -> [a]
++ h -> String
forall a. Name a => a -> String
name h
s
                    String -> String -> String
forall a. [a] -> [a] -> [a]
++ i -> String
forall a. Name a => a -> String
name i
r String -> String -> String
forall a. [a] -> [a] -> [a]
++ j -> String
forall a. Name a => a -> String
name j
q String -> String -> String
forall a. [a] -> [a] -> [a]
++ k -> String
forall a. Name a => a -> String
name k
p
    where  (a
x,b
y,c
z,d
w,e
v,f
u,g
t,h
s,i
r,j
q,k
p)  =  (a, b, c, d, e, f, g, h, i, j, k)
xyzwvutsrqp

instance ( Name a, Name b, Name c, Name d
         , Name e, Name f, Name g, Name h
         , Name i, Name j, Name k, Name l )
      => Name (a,b,c,d,e,f,g,h,i,j,k,l) where
  name :: (a, b, c, d, e, f, g, h, i, j, k, l) -> String
name (a, b, c, d, e, f, g, h, i, j, k, l)
xyzwvutsrqpo  =  a -> String
forall a. Name a => a -> String
name a
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ b -> String
forall a. Name a => a -> String
name b
y String -> String -> String
forall a. [a] -> [a] -> [a]
++ c -> String
forall a. Name a => a -> String
name c
z String -> String -> String
forall a. [a] -> [a] -> [a]
++ d -> String
forall a. Name a => a -> String
name d
w
                     String -> String -> String
forall a. [a] -> [a] -> [a]
++ e -> String
forall a. Name a => a -> String
name e
v String -> String -> String
forall a. [a] -> [a] -> [a]
++ f -> String
forall a. Name a => a -> String
name f
u String -> String -> String
forall a. [a] -> [a] -> [a]
++ g -> String
forall a. Name a => a -> String
name g
t String -> String -> String
forall a. [a] -> [a] -> [a]
++ h -> String
forall a. Name a => a -> String
name h
s
                     String -> String -> String
forall a. [a] -> [a] -> [a]
++ i -> String
forall a. Name a => a -> String
name i
r String -> String -> String
forall a. [a] -> [a] -> [a]
++ j -> String
forall a. Name a => a -> String
name j
q String -> String -> String
forall a. [a] -> [a] -> [a]
++ k -> String
forall a. Name a => a -> String
name k
p String -> String -> String
forall a. [a] -> [a] -> [a]
++ l -> String
forall a. Name a => a -> String
name l
o
    where  (a
x,b
y,c
z,d
w,e
v,f
u,g
t,h
s,i
r,j
q,k
p,l
o)  =  (a, b, c, d, e, f, g, h, i, j, k, l)
xyzwvutsrqpo