{-# 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
(DNA -> DNA -> Bool) -> (DNA -> DNA -> Bool) -> Eq DNA
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
Eq DNA
-> (DNA -> DNA -> Ordering)
-> (DNA -> DNA -> Bool)
-> (DNA -> DNA -> Bool)
-> (DNA -> DNA -> Bool)
-> (DNA -> DNA -> Bool)
-> (DNA -> DNA -> DNA)
-> (DNA -> DNA -> DNA)
-> Ord 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
$cp1Ord :: Eq DNA
Ord, DNA
DNA -> DNA -> Bounded 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]
(DNA -> DNA)
-> (DNA -> DNA)
-> (Int -> DNA)
-> (DNA -> Int)
-> (DNA -> [DNA])
-> (DNA -> DNA -> [DNA])
-> (DNA -> DNA -> [DNA])
-> (DNA -> DNA -> DNA -> [DNA])
-> Enum 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. DNA -> Rep DNA x)
-> (forall x. Rep DNA x -> DNA) -> Generic DNA
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 -> ()
(DNA -> ()) -> NFData 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
(RNA -> RNA -> Bool) -> (RNA -> RNA -> Bool) -> Eq RNA
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
Eq RNA
-> (RNA -> RNA -> Ordering)
-> (RNA -> RNA -> Bool)
-> (RNA -> RNA -> Bool)
-> (RNA -> RNA -> Bool)
-> (RNA -> RNA -> Bool)
-> (RNA -> RNA -> RNA)
-> (RNA -> RNA -> RNA)
-> Ord 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
$cp1Ord :: Eq RNA
Ord, RNA
RNA -> RNA -> Bounded 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]
(RNA -> RNA)
-> (RNA -> RNA)
-> (Int -> RNA)
-> (RNA -> Int)
-> (RNA -> [RNA])
-> (RNA -> RNA -> [RNA])
-> (RNA -> RNA -> [RNA])
-> (RNA -> RNA -> RNA -> [RNA])
-> Enum 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. RNA -> Rep RNA x)
-> (forall x. Rep RNA x -> RNA) -> Generic RNA
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 -> ()
(RNA -> ()) -> NFData 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 :: p RNA (f RNA) -> p DNA (f DNA)
nucleoIso = (DNA -> RNA) -> (RNA -> DNA) -> Iso DNA DNA RNA RNA
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 = DNA -> DNA
forall a. Complementary a => a -> a
cNA

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

    rcNA :: RNA -> RNA
rcNA = RNA -> RNA
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 = Char -> Char
forall a. Complementary a => a -> a
cNA

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

   rcNA :: [a] -> [a]
rcNA = [a] -> [a]
forall a. [a] -> [a]
reverse ([a] -> [a]) -> ([a] -> [a]) -> [a] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> [a]
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 = (a -> a) -> Array i a -> Array i a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> a
forall a. Complementary a => a -> a
cNA

   rcNA :: Array i a -> Array i a
rcNA Array i a
l = (i, i) -> [a] -> Array i a
forall i e. Ix i => (i, i) -> [e] -> Array i e
listArray (Array i a -> (i, i)
forall i e. Array i e -> (i, i)
bounds Array i a
l) [a]
rl
     where
       rl :: [a]
rl = [a] -> [a]
forall a. Complementary a => a -> a
rcNA ([a] -> [a]) -> (Array i a -> [a]) -> Array i a -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Array i a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Array i a -> [a]) -> Array i a -> [a]
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 = (a -> a) -> Array Int a -> Array Int a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> a
forall a. Complementary a => a -> a
cNA

   rcNA :: Array Int a -> Array Int a
rcNA Array Int a
l = Array Int a -> Array Int a
forall a. Complementary a => a -> a
cNA (Array Int a -> Array Int a) -> Array Int a -> Array Int a
forall a b. (a -> b) -> a -> b
$ (Int, Int) -> (Int -> Int) -> Array Int a -> Array Int a
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 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (Int
hi Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
i)) Array Int a
l
     where
       (Int
lo, Int
hi) = Array Int a -> (Int, Int)
forall i e. Array i e -> (i, i)
bounds Array Int a
l