{-# LANGUAGE DeriveAnyClass #-}

module Bio.NucleicAcid.Nucleotide.Type
  ( DNA (..)
  , RNA (..)
  , nucleoIso
  , toRNA
  , toDNA
  , Complementary (..)
  ) where

import Control.DeepSeq (NFData)
import Control.Lens    (Iso', iso)
import Data.Array      (Array, Ix, bounds, ixmap, listArray)
import Data.Foldable   (Foldable (..))
import GHC.Generics    (Generic)

data DNA
  = DA
  | DC
  | DG
  | DT
  deriving (DNA -> DNA -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DNA -> DNA -> Bool
$c/= :: DNA -> DNA -> Bool
== :: DNA -> DNA -> Bool
$c== :: DNA -> DNA -> Bool
Eq, Eq DNA
DNA -> DNA -> Bool
DNA -> DNA -> Ordering
DNA -> DNA -> DNA
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: DNA -> DNA -> DNA
$cmin :: DNA -> DNA -> DNA
max :: DNA -> DNA -> DNA
$cmax :: DNA -> DNA -> DNA
>= :: DNA -> DNA -> Bool
$c>= :: DNA -> DNA -> Bool
> :: DNA -> DNA -> Bool
$c> :: DNA -> DNA -> Bool
<= :: DNA -> DNA -> Bool
$c<= :: DNA -> DNA -> Bool
< :: DNA -> DNA -> Bool
$c< :: DNA -> DNA -> Bool
compare :: DNA -> DNA -> Ordering
$ccompare :: DNA -> DNA -> Ordering
Ord, DNA
forall a. a -> a -> Bounded a
maxBound :: DNA
$cmaxBound :: DNA
minBound :: DNA
$cminBound :: DNA
Bounded, Int -> DNA
DNA -> Int
DNA -> [DNA]
DNA -> DNA
DNA -> DNA -> [DNA]
DNA -> DNA -> DNA -> [DNA]
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: DNA -> DNA -> DNA -> [DNA]
$cenumFromThenTo :: DNA -> DNA -> DNA -> [DNA]
enumFromTo :: DNA -> DNA -> [DNA]
$cenumFromTo :: DNA -> DNA -> [DNA]
enumFromThen :: DNA -> DNA -> [DNA]
$cenumFromThen :: DNA -> DNA -> [DNA]
enumFrom :: DNA -> [DNA]
$cenumFrom :: DNA -> [DNA]
fromEnum :: DNA -> Int
$cfromEnum :: DNA -> Int
toEnum :: Int -> DNA
$ctoEnum :: Int -> DNA
pred :: DNA -> DNA
$cpred :: DNA -> DNA
succ :: DNA -> DNA
$csucc :: DNA -> DNA
Enum, forall x. Rep DNA x -> DNA
forall x. DNA -> Rep DNA x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep DNA x -> DNA
$cfrom :: forall x. DNA -> Rep DNA x
Generic, DNA -> ()
forall a. (a -> ()) -> NFData a
rnf :: DNA -> ()
$crnf :: DNA -> ()
NFData)

instance Show DNA where
    show :: DNA -> String
show DNA
DA = String
"Adenine"
    show DNA
DC = String
"Cytosine"
    show DNA
DG = String
"Guanine"
    show DNA
DT = String
"Thymine"

data RNA
  = RA
  | RC
  | RG
  | RU
  deriving (RNA -> RNA -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RNA -> RNA -> Bool
$c/= :: RNA -> RNA -> Bool
== :: RNA -> RNA -> Bool
$c== :: RNA -> RNA -> Bool
Eq, Eq RNA
RNA -> RNA -> Bool
RNA -> RNA -> Ordering
RNA -> RNA -> RNA
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: RNA -> RNA -> RNA
$cmin :: RNA -> RNA -> RNA
max :: RNA -> RNA -> RNA
$cmax :: RNA -> RNA -> RNA
>= :: RNA -> RNA -> Bool
$c>= :: RNA -> RNA -> Bool
> :: RNA -> RNA -> Bool
$c> :: RNA -> RNA -> Bool
<= :: RNA -> RNA -> Bool
$c<= :: RNA -> RNA -> Bool
< :: RNA -> RNA -> Bool
$c< :: RNA -> RNA -> Bool
compare :: RNA -> RNA -> Ordering
$ccompare :: RNA -> RNA -> Ordering
Ord, RNA
forall a. a -> a -> Bounded a
maxBound :: RNA
$cmaxBound :: RNA
minBound :: RNA
$cminBound :: RNA
Bounded, Int -> RNA
RNA -> Int
RNA -> [RNA]
RNA -> RNA
RNA -> RNA -> [RNA]
RNA -> RNA -> RNA -> [RNA]
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: RNA -> RNA -> RNA -> [RNA]
$cenumFromThenTo :: RNA -> RNA -> RNA -> [RNA]
enumFromTo :: RNA -> RNA -> [RNA]
$cenumFromTo :: RNA -> RNA -> [RNA]
enumFromThen :: RNA -> RNA -> [RNA]
$cenumFromThen :: RNA -> RNA -> [RNA]
enumFrom :: RNA -> [RNA]
$cenumFrom :: RNA -> [RNA]
fromEnum :: RNA -> Int
$cfromEnum :: RNA -> Int
toEnum :: Int -> RNA
$ctoEnum :: Int -> RNA
pred :: RNA -> RNA
$cpred :: RNA -> RNA
succ :: RNA -> RNA
$csucc :: RNA -> RNA
Enum, forall x. Rep RNA x -> RNA
forall x. RNA -> Rep RNA x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep RNA x -> RNA
$cfrom :: forall x. RNA -> Rep RNA x
Generic, RNA -> ()
forall a. (a -> ()) -> NFData a
rnf :: RNA -> ()
$crnf :: RNA -> ()
NFData)

instance Show RNA where
    show :: RNA -> String
show RNA
RA = String
"Adenine"
    show RNA
RC = String
"Cytosine"
    show RNA
RG = String
"Guanine"
    show RNA
RU = String
"Uracil"

-------------------------------------------------------------------------------
-- Transciption
-------------------------------------------------------------------------------

nucleoIso :: Iso' DNA RNA
nucleoIso :: Iso' DNA RNA
nucleoIso = forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso DNA -> RNA
toRNA RNA -> DNA
toDNA

{-# INLINE toRNA #-}
toRNA :: DNA -> RNA
toRNA :: DNA -> RNA
toRNA DNA
DA = RNA
RA
toRNA DNA
DC = RNA
RC
toRNA DNA
DG = RNA
RG
toRNA DNA
DT = RNA
RU

{-# INLINE toDNA #-}
toDNA :: RNA -> DNA
toDNA :: RNA -> DNA
toDNA RNA
RA = DNA
DA
toDNA RNA
RC = DNA
DC
toDNA RNA
RG = DNA
DG
toDNA RNA
RU = DNA
DT

------------------------------------------------------------------------------
-- Complementary and reverse complementary
-------------------------------------------------------------------------------

class Complementary a where
    -- | complement *NA (DNA or RNA)
    --
    cNA :: a -> a

    -- | reverce complement *NA (DNA or RNA)
    --
    rcNA :: a -> a

instance Complementary DNA where
    cNA :: DNA -> DNA
cNA DNA
DA = DNA
DT
    cNA DNA
DC = DNA
DG
    cNA DNA
DG = DNA
DC
    cNA DNA
DT = DNA
DA

    rcNA :: DNA -> DNA
rcNA = forall a. Complementary a => a -> a
cNA

instance Complementary RNA where
    cNA :: RNA -> RNA
cNA = DNA -> RNA
toRNA forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Complementary a => a -> a
cNA forall b c a. (b -> c) -> (a -> b) -> a -> c
. RNA -> DNA
toDNA

    rcNA :: RNA -> RNA
rcNA = forall a. Complementary a => a -> a
cNA

instance Complementary Char where
    cNA :: Char -> Char
cNA Char
'A' = Char
'T'
    cNA Char
'C' = Char
'G'
    cNA Char
'G' = Char
'C'
    cNA Char
'T' = Char
'A'
    cNA Char
'a' = Char
't'
    cNA Char
'c' = Char
'g'
    cNA Char
'g' = Char
'c'
    cNA Char
't' = Char
'a'
    cNA Char
c = Char
c

    rcNA :: Char -> Char
rcNA = forall a. Complementary a => a -> a
cNA

instance Complementary a => Complementary [a] where
   cNA :: [a] -> [a]
cNA = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. Complementary a => a -> a
cNA

   rcNA :: [a] -> [a]
rcNA = forall a. [a] -> [a]
reverse forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Complementary a => a -> a
cNA

instance {-# OVERLAPPABLE #-} (Complementary a, Ix i) => Complementary (Array i a) where
   cNA :: Array i a -> Array i a
cNA = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. Complementary a => a -> a
cNA

   rcNA :: Array i a -> Array i a
rcNA Array i a
l = forall i e. Ix i => (i, i) -> [e] -> Array i e
listArray (forall i e. Array i e -> (i, i)
bounds Array i a
l) [a]
rl
     where
       rl :: [a]
rl = forall a. Complementary a => a -> a
rcNA forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => t a -> [a]
toList forall a b. (a -> b) -> a -> b
$ Array i a
l

instance {-# OVERLAPPING  #-} (Complementary a) => Complementary (Array Int a) where
   cNA :: Array Int a -> Array Int a
cNA = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. Complementary a => a -> a
cNA

   rcNA :: Array Int a -> Array Int a
rcNA Array Int a
l = forall a. Complementary a => a -> a
cNA forall a b. (a -> b) -> a -> b
$ forall i j e.
(Ix i, Ix j) =>
(i, i) -> (i -> j) -> Array j e -> Array i e
ixmap (Int
lo, Int
hi) (\Int
i -> Int
lo forall a. Num a => a -> a -> a
+ (Int
hi forall a. Num a => a -> a -> a
- Int
i)) Array Int a
l
     where
       (Int
lo, Int
hi) = forall i e. Array i e -> (i, i)
bounds Array Int a
l