diff --git a/Biobase/Types/AminoAcidSequence.hs b/Biobase/Types/AminoAcidSequence.hs
deleted file mode 100644
--- a/Biobase/Types/AminoAcidSequence.hs
+++ /dev/null
@@ -1,59 +0,0 @@
-
--- | Encode the allowed amino acids in a better way.
-
-module Biobase.Types.AminoAcidSequence where
-
-import           Control.DeepSeq
-import           Control.Lens
-import           Data.ByteString (ByteString)
-import           Data.Char (ord,chr,toUpper)
-import           Data.Data (Data)
-import           Data.Typeable (Typeable)
-import           GHC.Exts (IsString(..))
-import           GHC.Generics (Generic)
-import qualified Data.ByteString.Char8 as BS
-import qualified Data.ByteString.UTF8 as BSU
-import           Test.QuickCheck (Arbitrary(..))
-import qualified Test.QuickCheck as TQ
-
-
-
--- | A short amino acid suquence.
---
--- It is an instance of 'Ixed' to allow @RNAseq (BS.pack "cag") ^? ix 2 == Just 'g'@.
-
-newtype AAseq = AAseq { _aaseq ∷ ByteString }
-  deriving (Data, Typeable, Generic, Eq, Ord, Read, Show)
-makeLenses ''AAseq
-
-instance NFData AAseq
-
-type instance Index AAseq = Int
-
-type instance IxValue AAseq = Char
-
-instance Ixed AAseq where
-  ix k = aaseq . ix k . iso (chr . fromIntegral) (fromIntegral . ord)
-  {-# Inline ix #-}
-
-deriving instance Reversing AAseq
-
-mkAAseq ∷ ByteString → AAseq
-mkAAseq = AAseq . BS.map go . BS.map toUpper
-  where go x | x `elem` aas = x
-             | otherwise    = 'X'
-        aas ∷ String
-        aas = "ARNDCEQGHILKMFPSTWYVUO"
-
-instance IsString AAseq where
-  fromString = mkAAseq . BS.pack
-
-instance Arbitrary AAseq where
-  arbitrary = do
-    k ← TQ.choose (0,100)
-    xs ← TQ.vectorOf k $ TQ.elements "ARNDCEQGHILKMFPSTWYVUO"
-    return . AAseq $ BS.pack xs
-  shrink = view (to shrink)
-
-
-
diff --git a/Biobase/Types/BioSequence.hs b/Biobase/Types/BioSequence.hs
new file mode 100644
--- /dev/null
+++ b/Biobase/Types/BioSequence.hs
@@ -0,0 +1,311 @@
+
+-- | Abstraction over bio sequences encoded as one-ascii character as one
+-- symbol. We phantom-type the exact bio-sequence type and provide type classes
+-- that act on known types.
+--
+-- Unknown bio sequences should be tagged with @Void@.
+
+module Biobase.Types.BioSequence where
+
+import           Control.DeepSeq
+import           Control.Lens
+import           Data.ByteString.Char8 (ByteString)
+import           Data.Char (ord,chr,toUpper)
+import           Data.Data (Data)
+import           Data.Typeable (Typeable)
+import           Data.Void
+import           GHC.Exts (IsString(..))
+import           GHC.Generics (Generic)
+import qualified Data.ByteString.Char8 as BS
+import qualified Test.QuickCheck as TQ
+import           Test.QuickCheck (Arbitrary(..))
+import qualified Data.ByteString.UTF8 as BSU
+
+import           Biobase.Types.Strand
+import qualified Biobase.Types.Index as BTI
+
+
+
+-- * Sequence identifiers
+
+newtype SequenceIdentifier (which ∷ k) = SequenceIdentifier { _sequenceIdentifier ∷ ByteString }
+  deriving (Data, Typeable, Generic, Eq, Ord, Read, Show)
+makeWrapped ''SequenceIdentifier
+makePrisms ''SequenceIdentifier
+
+instance NFData (SequenceIdentifier w)
+
+instance IsString (SequenceIdentifier w) where
+  fromString = SequenceIdentifier . BSU.fromString
+
+
+
+-- * Bio-Sequences
+
+data RNA
+
+data DNA
+
+data XNA
+
+data AA
+
+
+
+newtype BioSequence (which ∷ k) = BioSequence {_bioSequence ∷ ByteString}
+  deriving (Data, Typeable, Generic, Eq, Ord, Read, Show, Semigroup)
+makeWrapped ''BioSequence
+makePrisms ''BioSequence
+
+instance NFData (BioSequence w)
+
+type instance Index (BioSequence w) = Int
+
+type instance IxValue (BioSequence w) = Char
+
+instance Ixed (BioSequence w) where
+  ix k = _BioSequence . ix k . iso (chr . fromIntegral) (fromIntegral . ord)
+  {-# Inline ix #-}
+
+deriving instance Reversing (BioSequence w)
+
+instance IsString (BioSequence Void) where
+  fromString = BioSequence . BS.pack
+
+
+
+-- * RNA
+
+mkRNAseq ∷ ByteString → BioSequence RNA
+mkRNAseq = BioSequence . BS.map go . BS.map toUpper
+  where go x | x `elem` acgu = x
+             | otherwise     = 'N'
+        acgu ∷ String
+        acgu = "ACGU"
+
+instance IsString (BioSequence RNA) where
+  fromString = mkRNAseq . BS.pack
+
+instance Arbitrary (BioSequence RNA) where
+  arbitrary = do
+    k ← TQ.choose (0,100)
+    xs ← TQ.vectorOf k $ TQ.elements "ACGU"
+    return . BioSequence $ BS.pack xs
+  shrink = view (to shrink)
+
+
+
+-- * DNA
+
+mkDNAseq ∷ ByteString → (BioSequence DNA)
+mkDNAseq = BioSequence . BS.map go . BS.map toUpper
+  where go x | x `elem` acgt = x
+             | otherwise     = 'N'
+        acgt ∷ String
+        acgt = "ACGT"
+
+instance IsString (BioSequence DNA) where
+  fromString = mkDNAseq . BS.pack
+
+instance Arbitrary (BioSequence DNA) where
+  arbitrary = do
+    k ← TQ.choose (0,100)
+    xs ← TQ.vectorOf k $ TQ.elements "ACGT"
+    return . BioSequence $ BS.pack xs
+  shrink = view (to shrink)
+
+
+
+-- * XNA
+
+mkXNAseq ∷ ByteString → (BioSequence XNA)
+mkXNAseq = BioSequence . BS.map go . BS.map toUpper
+  where go x | x `elem` acgtu = x
+             | otherwise      = 'N'
+        acgtu ∷ String
+        acgtu = "ACGTU"
+
+instance IsString (BioSequence XNA) where
+  fromString = mkXNAseq . BS.pack
+
+instance Arbitrary (BioSequence XNA) where
+  arbitrary = do
+    k ← TQ.choose (0,100)
+    xs ← TQ.vectorOf k $ TQ.elements "ACGTU"
+    return . BioSequence $ BS.pack xs
+  shrink = view (to shrink)
+
+
+
+-- * Amino acid sequences
+
+mkAAseq ∷ ByteString → (BioSequence AA)
+mkAAseq = BioSequence . BS.map go . BS.map toUpper
+  where go x | x `elem` aas = x
+             | otherwise    = 'X'
+        aas ∷ String
+        aas = "ARNDCEQGHILKMFPSTWYVUO"
+
+instance IsString (BioSequence AA) where
+  fromString = mkAAseq . BS.pack
+
+instance Arbitrary (BioSequence AA) where
+  arbitrary = do
+    k ← TQ.choose (0,100)
+    xs ← TQ.vectorOf k $ TQ.elements "ARNDCEQGHILKMFPSTWYVUO"
+    return . BioSequence $ BS.pack xs
+  shrink = view (to shrink)
+
+
+
+-- * A window into a longer sequence with prefix/suffix information.
+
+-- | Phantom-typed over two types, the type @w@ of the identifier, which can be
+-- descriptive ("FirstInput") and the second type, identifying what kind of
+-- sequence types we are dealing with. Finally, the third type fixes the index
+-- type of the infix.
+
+data BioSequenceWindow w ty k = BioSequenceWindow
+  { _bswIdentifier ∷ !(SequenceIdentifier w)
+    -- ^ Identifier for this window. Typically some fasta identifier
+  , _bswPrefix     ∷ !(BioSequence ty)
+    -- ^ Any prefix for this sequence
+  , _bswSequence   ∷ !(BioSequence ty)
+    -- ^ The actual sequence, the infix
+  , _bswSuffix     ∷ !(BioSequence ty)
+    -- ^ any suffix
+  , _bswStrand     ∷ !Strand
+    -- ^ strand information. Probably '+' but arbitrary
+  , _bswIndex ∷ !(BTI.Index k)
+    -- ^ Provide the index for the left-most character of the @bswSequence@ on
+    -- '+' on '-' as well, but to be interpreted on the '+' strand.
+    -- TODO this actually needs a more complicated encoding...!
+  }
+  deriving (Data, Typeable, Generic, Eq, Ord, Read, Show)
+makeLenses ''BioSequenceWindow
+
+instance Reversing (BioSequenceWindow w ty k) where
+  {-# Inlinable reversing #-}
+  reversing bsw = bsw
+                & bswPrefix .~ (bsw^.bswSuffix.reversed)
+                & bswSuffix .~ (bsw^.bswPrefix.reversed)
+                & bswSequence .~ (bsw^.bswSequence.reversed)
+                & bswStrand .~ (bsw^.bswStrand.reversed)
+
+-- | A lens into the full sequence information of a sequence window. One should
+-- *NOT* modify the length of the individual sequences.
+
+bswFullSequence ∷ Lens' (BioSequenceWindow w ty k) (BioSequence ty)
+{-# Inlinable bswFullSequence #-}
+bswFullSequence = lens f t
+  where f bsw = bsw^.bswPrefix <> bsw^.bswSequence <> bsw^.bswSuffix
+        t bsw (BioSequence s) =
+          let (pfx,ifxsfx) = BS.splitAt (bsw^.bswPrefix._BioSequence.to BS.length) s
+              (ifx,sfx) = BS.splitAt (bsw^.bswSequence._BioSequence.to BS.length) ifxsfx
+          in  bsw & bswPrefix._BioSequence .~ pfx
+                  & bswSequence._BioSequence .~ ifx
+                  & bswSuffix._BioSequence .~ sfx
+
+
+
+-- * DNA/RNA
+
+-- | Simple case translation from @U@ to @T@. with upper and lower-case
+-- awareness.
+
+rna2dna ∷ Char → Char
+rna2dna = \case
+  'U' → 'T'
+  'u' → 't'
+  x   → x
+{-# Inline rna2dna #-}
+
+-- | Single character RNA complement.
+
+rnaComplement ∷ Char → Char
+rnaComplement = \case
+  'A' → 'U'
+  'a' → 'u'
+  'C' → 'G'
+  'c' → 'g'
+  'G' → 'C'
+  'g' → 'c'
+  'U' → 'A'
+  'u' → 'a'
+  x   → x
+{-# Inline rnaComplement #-}
+
+-- | Simple case translation from @T@ to @U@ with upper- and lower-case
+-- awareness.
+
+dna2rna ∷ Char → Char
+dna2rna = \case
+  'T' → 'U'
+  't' → 'u'
+  x   → x
+{-# Inline dna2rna #-}
+
+-- | Single character DNA complement.
+
+dnaComplement ∷ Char → Char
+dnaComplement = \case
+  'A' → 'T'
+  'a' → 't'
+  'C' → 'G'
+  'c' → 'g'
+  'G' → 'C'
+  'g' → 'c'
+  'T' → 'A'
+  't' → 'a'
+  x   → x
+{-# Inline dnaComplement #-}
+
+
+
+-- | Transcribes a DNA sequence into an RNA sequence. Note that 'transcribe' is
+-- actually very generic. We just define its semantics to be that of
+-- biomolecular transcription.
+--
+-- 'transcribe' makes the assumption that, given @DNA -> RNA@, we transcribe
+-- the coding strand.
+-- <http://hyperphysics.phy-astr.gsu.edu/hbase/Organic/transcription.html>
+--
+-- @@ DNAseq "ACGT" ^. transcribe == RNAseq "ACGU" RNAseq "ACGU" ^. transcribe
+-- == DNAseq "ACGT" RNAseq "ACGU" ^. from transcribe :: DNAseq == DNAseq "ACGT"
+-- @@
+
+class Transcribe f where
+  type TranscribeTo f ∷ *
+  transcribe ∷ Iso' f (TranscribeTo f)
+
+-- | Transcribe a DNA sequence into an RNA sequence. This does not @reverse@
+-- the sequence!
+
+instance Transcribe (BioSequence DNA) where
+  type TranscribeTo (BioSequence DNA) = (BioSequence RNA)
+  transcribe = iso (over _BioSequence (BS.map dna2rna)) (over _BioSequence (BS.map rna2dna))
+  {-# Inline transcribe #-}
+
+-- | Transcribe a RNA sequence into an DNA sequence. This does not @reverse@
+-- the sequence!
+
+instance Transcribe (BioSequence RNA) where
+  type TranscribeTo (BioSequence RNA) = (BioSequence DNA)
+  transcribe = from transcribe
+  {-# Inline transcribe #-}
+
+
+
+-- | The complement of a biosequence.
+
+class Complement f where
+  complement ∷ Iso' f f
+
+instance Complement (BioSequence DNA) where
+  complement = iso (over _BioSequence (BS.map dnaComplement)) (over _BioSequence (BS.map dnaComplement))
+  {-# Inline complement #-}
+
+instance Complement (BioSequence RNA) where
+  complement = iso (over _BioSequence (BS.map rnaComplement)) (over _BioSequence (BS.map rnaComplement))
+  {-# Inline complement #-}
+
diff --git a/Biobase/Types/Bitscore.hs b/Biobase/Types/Bitscore.hs
--- a/Biobase/Types/Bitscore.hs
+++ b/Biobase/Types/Bitscore.hs
@@ -26,6 +26,7 @@
 import qualified Data.Vector.Generic.Mutable as VGM
 import qualified Data.Vector.Unboxed as VU
 
+import           Algebra.Structure.Semiring
 import           Numeric.Limits
 
 
@@ -40,6 +41,16 @@
 
 newtype Bitscore = Bitscore { getBitscore :: Double }
   deriving (Eq,Ord,Read,Show,Num,Fractional,Generic)
+
+instance Semiring Bitscore where
+  plus = (+)
+  times = (*)
+  zero = 0
+  one = 1
+  {-# Inline plus  #-}
+  {-# Inline times #-}
+  {-# Inline zero  #-}
+  {-# Inline one   #-}
 
 instance Binary    Bitscore
 instance FromJSON  Bitscore
diff --git a/Biobase/Types/Codon.hs b/Biobase/Types/Codon.hs
new file mode 100644
--- /dev/null
+++ b/Biobase/Types/Codon.hs
@@ -0,0 +1,20 @@
+
+module Biobase.Types.Codon where
+
+import Control.Lens
+import GHC.Generics (Generic)
+
+
+
+-- | A single codon.
+--
+-- TODO needs to go into its own place
+
+data Codon c = Codon !c !c !c
+  deriving (Eq,Ord,Read,Show,Generic,Functor,Foldable,Traversable)
+
+instance Field1 (Codon c) (Codon c) c c
+instance Field2 (Codon c) (Codon c) c c
+instance Field3 (Codon c) (Codon c) c c
+instance Each (Codon c) (Codon c') c c'
+
diff --git a/Biobase/Types/Energy.hs b/Biobase/Types/Energy.hs
--- a/Biobase/Types/Energy.hs
+++ b/Biobase/Types/Energy.hs
@@ -13,6 +13,7 @@
 import Data.Data
 import Data.Default
 import Data.Hashable
+import GHC.Real
 import Data.Serialize (Serialize)
 import Data.Vector.Unboxed.Deriving
 import GHC.Generics
@@ -56,8 +57,8 @@
 
 -- | Discretized @DG@.
 
-newtype DDG = DDG { dDG ∷ Discretized 1 100 }
-  deriving (Eq,Ord,Num,Read,Show,Generic,Integral,Real,Enum)
+newtype DDG = DDG { dDG ∷ Discretized (1 :% 100) }
+  deriving (Eq,Ord,Num,Read,Show,Generic,Real,Enum)
 
 derivingUnbox "DDG"
   [t| DDG → Int |]  [| getDiscretized . dDG |]  [| DDG . Discretized |]
diff --git a/Biobase/Types/Evalue.hs b/Biobase/Types/Evalue.hs
--- a/Biobase/Types/Evalue.hs
+++ b/Biobase/Types/Evalue.hs
@@ -8,6 +8,7 @@
 module Biobase.Types.Evalue where
 
 import           Control.DeepSeq
+import           Control.Lens
 import           Data.Aeson
 import           Data.Binary
 import           Data.Default
@@ -29,6 +30,7 @@
 
 newtype Evalue = Evalue { getEvalue :: Double }
   deriving (Eq,Ord,Read,Show,Num,Generic)
+makeWrapped ''Evalue
 
 instance Binary    Evalue
 instance FromJSON  Evalue
diff --git a/Biobase/Types/Index.hs b/Biobase/Types/Index.hs
--- a/Biobase/Types/Index.hs
+++ b/Biobase/Types/Index.hs
@@ -53,30 +53,24 @@
 (+.) i n = checkIndex $ unsafePlus i n
 {-# Inline (+.) #-}
 
--- | Unsafe plus.
-
-unsafePlus :: forall t . KnownNat t => Index t -> Int -> Index t
-unsafePlus i n = Index $ IT.getIndex i + n
-{-# Inline unsafePlus #-}
-
 -- | Helper function that allows @subtraction@ of an 'Index' and an 'Int',
 -- with the 'Int' on the right.
 
 (-.) :: forall t . KnownNat t => Index t -> Int -> Index t
-(-.) i n = checkIndex $ unsafeMinus i n
+(-.) i n = checkIndex $ unsafePlus i n
 {-# Inline (-.) #-}
 
+-- | Unsafe plus.
+
+unsafePlus :: forall t . KnownNat t => Index t -> Int -> Index t
+unsafePlus i n = Index $ IT.getIndex i + n
+{-# Inline unsafePlus #-}
+
 -- | Delta between two 'Index' points.
 
 delta :: forall t . KnownNat t => Index t -> Index t -> Int
 delta i j = abs . IT.getIndex $ i - j
 {-# Inline delta #-}
-
--- | Unsafe minus.
-
-unsafeMinus :: forall t . KnownNat t => Index t -> Int -> Index t
-unsafeMinus i n = Index $ IT.getIndex i - n
-{-# Inline unsafeMinus #-}
 
 toInt ∷ forall t . KnownNat t ⇒ Index t → Int
 {-# Inline toInt #-}
diff --git a/Biobase/Types/Index/Type.hs b/Biobase/Types/Index/Type.hs
--- a/Biobase/Types/Index/Type.hs
+++ b/Biobase/Types/Index/Type.hs
@@ -5,15 +5,17 @@
 import           Control.DeepSeq
 import           Data.Aeson
 import           Data.Binary
+import           Data.Data (Data)
 import           Data.Hashable (Hashable)
 import           Data.Proxy
 import           Data.Serialize (Serialize)
+import           Data.Typeable (Typeable)
 import           Data.Vector.Fusion.Stream.Monadic (Step(..), flatten)
-import qualified Data.Vector.Fusion.Stream.Monadic as SM
 import           Data.Vector.Unboxed.Deriving
 import           GHC.Generics
 import           GHC.TypeLits
 import qualified Data.Ix as Ix
+import qualified Data.Vector.Fusion.Stream.Monadic as SM
 import           Test.QuickCheck
 import           Text.Printf
 
@@ -25,7 +27,7 @@
 -- | A linear @Int@-based index type.
 
 newtype Index (t :: Nat) = Index { getIndex :: Int }
-  deriving (Show,Read,Eq,Ord,Generic,Ix.Ix)
+  deriving (Show,Read,Eq,Ord,Generic,Ix.Ix,Data,Typeable)
 
 -- | Turn an 'Int' into an 'Index' safely.
 
@@ -44,9 +46,9 @@
 {-# Inline maybeIndex #-}
 
 instance KnownNat t => Num (Index t) where
-  Index a + Index b = error "not implemented, use (+.)" -- index $ a + b
-  Index a - Index b = error "not implemented, use (-.)" -- index $ a - b
-  Index a * Index b = error "not implemented" -- index $ a * b
+  Index a + Index b = error $ show (" Index.(+) not implemented, use (+.)",a,b) -- index $ a + b
+  Index a - Index b = error $ show (" Index.(-) not implemented, use (-.)",a,b) -- index $ a - b
+  Index a * Index b = error $ show (" Index.(*) not implemented", a,b) -- index $ a * b
   negate = error "Indices are natural numbers"
   abs = id
   signum = index . signum . getIndex
diff --git a/Biobase/Types/NucleotideSequence.hs b/Biobase/Types/NucleotideSequence.hs
deleted file mode 100644
--- a/Biobase/Types/NucleotideSequence.hs
+++ /dev/null
@@ -1,217 +0,0 @@
-
--- | Wrappers around biosequences.
-
-module Biobase.Types.NucleotideSequence where
-
-import           Control.DeepSeq
-import           Control.Lens
-import           Data.ByteString (ByteString)
-import           Data.Char (ord,chr,toUpper)
-import           Data.Data (Data)
-import           Data.Typeable (Typeable)
-import           GHC.Exts (IsString(..))
-import           GHC.Generics (Generic)
-import qualified Data.ByteString.Char8 as BS
-import qualified Data.ByteString.UTF8 as BSU
-import           Test.QuickCheck (Arbitrary(..))
-import qualified Test.QuickCheck as TQ
-
-
-
--- | A sequence identifier. Just a newtype wrapped text field. Because we can
--- never know what people are up to, this is utf8-encoded.
---
--- TODO Provide @Iso'@ for @Text@, too?
---
--- TODO move into @Biobase.Types.SequenceID@
-
-newtype SequenceID = SequenceID { _sequenceID ∷ ByteString }
-  deriving (Data, Typeable, Generic, Eq, Ord, Read, Show, IsString)
-makeLenses ''SequenceID
-
-instance NFData SequenceID
-
--- | Convert to a string in a unicode-aware manner.
-
-sequenceIDstring ∷ Iso' SequenceID String
-sequenceIDstring = sequenceID . iso BSU.toString BSU.fromString
-{-# Inline sequenceIDstring #-}
-
-
-
--- | A short RNA sequence.
---
--- It is an instance of 'Ixed' to allow @RNAseq (BS.pack "cag") ^? ix 2 == Just 'g'@.
-
-newtype RNAseq = RNAseq { _rnaseq ∷ ByteString }
-  deriving (Data, Typeable, Generic, Eq, Ord, Read, Show)
-makeLenses ''RNAseq
-
-instance NFData RNAseq
-
-type instance Index RNAseq = Int
-
-type instance IxValue RNAseq = Char
-
-instance Ixed RNAseq where
-  ix k = rnaseq . ix k . iso (chr . fromIntegral) (fromIntegral . ord)
-  {-# Inline ix #-}
-
-deriving instance Reversing RNAseq
-
-mkRNAseq ∷ ByteString → RNAseq
-mkRNAseq = RNAseq . BS.map go . BS.map toUpper
-  where go x | x `elem` acgu = x
-             | otherwise     = 'N'
-        acgu ∷ String
-        acgu = "ACGU"
-
-instance IsString RNAseq where
-  fromString = mkRNAseq . BS.pack
-
-instance Arbitrary RNAseq where
-  arbitrary = do
-    k ← TQ.choose (0,100)
-    xs ← TQ.vectorOf k $ TQ.elements "ACGU"
-    return . RNAseq $ BS.pack xs
-  shrink = view (to shrink)
-
-
-
--- | A short DNA sequence.
---
--- Note everything really long should be handled by specialized libraries with
--- streaming capabilities.
-
-newtype DNAseq = DNAseq { _dnaseq ∷ ByteString }
-  deriving (Data, Typeable, Generic, Eq, Ord, Read, Show)
-makeLenses ''DNAseq
-
-instance NFData DNAseq
-
-type instance Index DNAseq = Int
-
-type instance IxValue DNAseq = Char
-
-instance Ixed DNAseq where
-  ix k = dnaseq . ix k . iso (chr . fromIntegral) (fromIntegral . ord)
-  {-# Inline ix #-}
-
-mkDNAseq ∷ ByteString → DNAseq
-mkDNAseq = DNAseq . BS.map go . BS.map toUpper
-  where go x | x `elem` acgt = x
-             | otherwise     = 'N'
-        acgt ∷ String
-        acgt = "ACGT"
-
-instance IsString DNAseq where
-  fromString = mkDNAseq . BS.pack
-
-deriving instance Reversing DNAseq
-
-instance Arbitrary DNAseq where
-  arbitrary = do
-    k ← TQ.choose (0,100)
-    xs ← TQ.vectorOf k $ TQ.elements "ACGT"
-    return . DNAseq $ BS.pack xs
-  shrink = view (to shrink)
-
--- | Simple case translation from @U@ to @T@. with upper and lower-case
--- awareness.
-
-rna2dna ∷ Char → Char
-rna2dna = \case
-  'U' → 'T'
-  'u' → 't'
-  x   → x
-{-# Inline rna2dna #-}
-
--- | Single character RNA complement.
-
-rnaComplement ∷ Char → Char
-rnaComplement = \case
-  'A' → 'U'
-  'a' → 'u'
-  'C' → 'G'
-  'c' → 'g'
-  'G' → 'C'
-  'g' → 'c'
-  'U' → 'A'
-  'u' → 'a'
-  x   → x
-{-# Inline rnaComplement #-}
-
--- | Simple case translation from @T@ to @U@ with upper- and lower-case
--- awareness.
-
-dna2rna ∷ Char → Char
-dna2rna = \case
-  'T' → 'U'
-  't' → 'u'
-  x   → x
-{-# Inline dna2rna #-}
-
--- | Single character DNA complement.
-
-dnaComplement ∷ Char → Char
-dnaComplement = \case
-  'A' → 'T'
-  'a' → 't'
-  'C' → 'G'
-  'c' → 'g'
-  'G' → 'C'
-  'g' → 'c'
-  'T' → 'A'
-  't' → 'a'
-  x   → x
-{-# Inline dnaComplement #-}
-
-
-
--- | Transcribes a DNA sequence into an RNA sequence. Note that 'transcribe' is
--- actually very generic. We just define its semantics to be that of
--- biomolecular transcription.
---
--- 'transcribe' makes the assumption that, given @DNA -> RNA@, we transcribe
--- the coding strand.
--- <http://hyperphysics.phy-astr.gsu.edu/hbase/Organic/transcription.html>
---
--- @@ DNAseq "ACGT" ^. transcribe == RNAseq "ACGU" RNAseq "ACGU" ^. transcribe
--- == DNAseq "ACGT" RNAseq "ACGU" ^. from transcribe :: DNAseq == DNAseq "ACGT"
--- @@
-
-class Transcribe f where
-  type TranscribeTo f ∷ *
-  transcribe ∷ Iso' f (TranscribeTo f)
-
--- | Transcribe a DNA sequence into an RNA sequence. This does not @reverse@
--- the sequence!
-
-instance Transcribe DNAseq where
-  type TranscribeTo DNAseq = RNAseq
-  transcribe = iso (RNAseq . BS.map dna2rna . _dnaseq) (DNAseq . BS.map rna2dna . _rnaseq)
-  {-# Inline transcribe #-}
-
--- | Transcribe a RNA sequence into an DNA sequence. This does not @reverse@
--- the sequence!
-
-instance Transcribe RNAseq where
-  type TranscribeTo RNAseq = DNAseq
-  transcribe = from transcribe
-  {-# Inline transcribe #-}
-
-
-
--- | The complement of a biosequence.
-
-class Complement f where
-  complement ∷ Iso' f f
-
-instance Complement DNAseq where
-  complement = iso (DNAseq . BS.map dnaComplement . _dnaseq) (DNAseq . BS.map dnaComplement . _dnaseq)
-  {-# Inline complement #-}
-
-instance Complement RNAseq where
-  complement = iso (RNAseq . BS.map rnaComplement . _rnaseq) (RNAseq . BS.map rnaComplement . _rnaseq)
-  {-# Inline complement #-}
-
diff --git a/Biobase/Types/ReadingFrame.hs b/Biobase/Types/ReadingFrame.hs
--- a/Biobase/Types/ReadingFrame.hs
+++ b/Biobase/Types/ReadingFrame.hs
@@ -1,29 +1,47 @@
 
+-- | Stranded reading frames.
+
 module Biobase.Types.ReadingFrame where
 
-import GHC.Generics
+import Control.Lens hiding (Index)
+import GHC.Generics hiding (from)
 
 import Biobase.Types.Index (Index, toInt0)
+import Biobase.Types.Strand
 
 
 
 -- | The Reading frame. Sequence indexing starts at position 1, which starts
 -- reading frame 1. Reading frame 2 and 3 start at position 2 and 3
 -- respectively.
---
--- The reading frame should be constructed from an @Index 1@ with a smart
--- constructor to get the frame calculation right.
 
 newtype ReadingFrame = ReadingFrame { getReadingFrame ∷ Int }
-  deriving (Eq,Ord,Generic)
+  deriving (Eq,Ord,Generic,Show)
+makeWrapped ''ReadingFrame
 
-nextReadingFrame ∷ ReadingFrame → ReadingFrame
-{-# Inline nextReadingFrame #-}
-nextReadingFrame (ReadingFrame rf) = ReadingFrame $ rf `mod` 3 + 1
+-- | Convert between @+1 ... +3@ and @ReadingFrame@.
 
-prevReadingFrame ∷ ReadingFrame → ReadingFrame
-{-# Inline prevReadingFrame #-}
-prevReadingFrame (ReadingFrame rf) = ReadingFrame $ rf `mod` 3 + 2
+rf ∷ Prism' Int ReadingFrame
+{-# Inline rf #-}
+rf = prism' getReadingFrame $ \k → let ak = abs k in
+  if (ak <=  3 && ak >= 1) then Just (ReadingFrame k) else Nothing
+
+-- | A lens for the strand
+
+strandRF ∷ Lens' ReadingFrame Strand
+{-# Inline strandRF #-}
+strandRF = lens (\(ReadingFrame k) → if k < 0 then MinusStrand else PlusStrand)
+                (\(ReadingFrame k) s → ReadingFrame $ if s == PlusStrand then abs k else (negate $ abs k))
+
+-- |
+--
+-- @pred@ and @succ@ are correct, if the input is a legal 'ReadingFrame'.
+
+instance Enum ReadingFrame where
+  {-# Inline toEnum #-}
+  toEnum k = case k^?rf of Just rf → rf ; Nothing → error $ show k ++ " is not a legal reading frame"
+  {-# Inline fromEnum #-}
+  fromEnum = getReadingFrame
 
 -- |
 --
diff --git a/Biobase/Types/Strand.hs b/Biobase/Types/Strand.hs
--- a/Biobase/Types/Strand.hs
+++ b/Biobase/Types/Strand.hs
@@ -8,11 +8,14 @@
 module Biobase.Types.Strand where
 
 import Control.DeepSeq
+import Control.Lens hiding (Index)
 import Control.Monad (guard)
 import Data.Aeson
 import Data.Binary
+import Data.Data (Data)
 import Data.Hashable (Hashable)
 import Data.Serialize (Serialize)
+import Data.Typeable (Typeable)
 import Data.Vector.Fusion.Stream.Monadic (Step(..), flatten)
 import Data.Vector.Unboxed.Deriving
 import GHC.Generics
@@ -27,7 +30,7 @@
 -- in, say, the FASTA file. 'MinusStrand' hence is the reverse complement.
 
 newtype Strand = Strand { getStrand :: Int }
-  deriving (Eq,Ord,Generic)
+  deriving (Eq,Ord,Generic,Data,Typeable)
 
 instance Show Strand where
   show PlusStrand  = "PlusStrand"
@@ -55,6 +58,10 @@
   toEnum i | i>=0 && i<=1 = Strand i
   toEnum i                = error $ "toEnum (Strand)" ++ show i
   fromEnum = getStrand
+
+instance Reversing Strand where
+  reversing PlusStrand = MinusStrand
+  reversing MinusStrand = PlusStrand
 
 pattern PlusStrand  = Strand 0
 pattern MinusStrand = Strand 1
diff --git a/BiobaseTypes.cabal b/BiobaseTypes.cabal
--- a/BiobaseTypes.cabal
+++ b/BiobaseTypes.cabal
@@ -1,7 +1,7 @@
 name:           BiobaseTypes
-version:        0.1.4.0
-author:         Christian Hoener zu Siederdissen, 2015 - 2018
-copyright:      Christian Hoener zu Siederdissen, 2015 - 2018
+version:        0.2.0.0
+author:         Christian Hoener zu Siederdissen, 2015 - 2019
+copyright:      Christian Hoener zu Siederdissen, 2015 - 2019
 homepage:       https://github.com/choener/BiobaseTypes
 bug-reports:    https://github.com/choener/BiobaseTypes/issues
 maintainer:     choener@bioinf.uni-leipzig.de
@@ -58,30 +58,34 @@
                --
                , bimaps                   == 0.1.0.*
                , ForestStructures         == 0.0.1.*
-               , PrimitiveArray           == 0.9.0.*
-               , SciBaseTypes             == 0.0.0.*
+               , PrimitiveArray           == 0.9.1.*
+               , SciBaseTypes             == 0.1.0.*
   exposed-modules:
     Biobase.Types.Accession
-    Biobase.Types.AminoAcidSequence
+    Biobase.Types.BioSequence
     Biobase.Types.Bitscore
+    Biobase.Types.Codon
     Biobase.Types.Energy
     Biobase.Types.Evalue
     Biobase.Types.Index
     Biobase.Types.Index.Type
     Biobase.Types.Names
     Biobase.Types.Names.Internal
-    Biobase.Types.NucleotideSequence
     Biobase.Types.ReadingFrame
     Biobase.Types.Shape
     Biobase.Types.Strand
     Biobase.Types.Structure
     Biobase.Types.Taxonomy
+    DP.Backtraced.BioSequence
+    DP.Backtraced.Codon
   default-language:
     Haskell2010
   default-extensions: BangPatterns
                     , DataKinds
                     , DeriveDataTypeable
+                    , DeriveFoldable
                     , DeriveGeneric
+                    , DeriveTraversable
                     , FlexibleContexts
                     , FlexibleInstances
                     , GeneralizedNewtypeDeriving
diff --git a/DP/Backtraced/BioSequence.hs b/DP/Backtraced/BioSequence.hs
new file mode 100644
--- /dev/null
+++ b/DP/Backtraced/BioSequence.hs
@@ -0,0 +1,3 @@
+
+module DP.Backtraced.BioSequence where
+
diff --git a/DP/Backtraced/Codon.hs b/DP/Backtraced/Codon.hs
new file mode 100644
--- /dev/null
+++ b/DP/Backtraced/Codon.hs
@@ -0,0 +1,46 @@
+
+-- | The Backtraced column structure is for codon-based alignments, including
+-- special cases.
+
+module DP.Backtraced.Codon where
+
+import Data.ByteString (ByteString)
+import Data.Vector (Vector)
+import GHC.Generics (Generic)
+
+import Biobase.Types.Codon
+
+
+
+-- | A single 'Backtraced' column. Since such a column will be part of a
+-- @Backtraced (Z:.BtCodon c aa:. ...)@ structure, it is always possible to
+-- extend even further, by having more entries.
+
+data BtCodon c aa
+  -- | A canonical match. A codon and the translated amino acid need to be set.
+  = Match
+    { _codon  ∷ !(Codon c)
+    , _aa     ∷ !aa
+    }
+  -- | A frameshifting match. The vector of frameshifted nucleotides will have
+  -- a number of characters @c@, that encode for a single amino acid.
+  | Frameshift
+    { _frameshift ∷ !(Vector c)
+    , _aa         ∷ !aa
+    }
+  | Insert
+    { _codon  ∷ !(Codon c)
+    , _aa     ∷ !aa
+    }
+  | Shifted
+    { _frameshift ∷ !(Vector c)
+    , _aa         ∷ !aa
+    }
+  | Region
+    { _region     ∷ !(Vector c)
+    , _annotation ∷ !ByteString
+    }
+  | Delete
+    {
+    }
+
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,8 @@
+0.2.0.0
+-------
+
+- unified treatment of bio sequences with one phantom-typed newtype.
+
 0.1.4.0
 -------
 
diff --git a/tests/properties.hs b/tests/properties.hs
--- a/tests/properties.hs
+++ b/tests/properties.hs
@@ -10,8 +10,8 @@
 import           Test.Tasty.QuickCheck (testProperty)
 import           Test.Tasty.TH
 
+import           Biobase.Types.BioSequence
 import           Biobase.Types.Bitscore
-import           Biobase.Types.NucleotideSequence
 import           Biobase.Types.Shape
 import           Biobase.Types.Structure
 
@@ -29,11 +29,11 @@
 
 -- complement twice
 
-prop_complement_twice_DNA (dna ∷ DNAseq) = dna == dna^.complement.complement
+prop_complement_twice_DNA (dna ∷ BioSequence DNA) = dna == dna^.complement.complement
 
-prop_complement_twice_RNA (rna ∷ RNAseq) = rna == rna^.complement.complement
+prop_complement_twice_RNA (rna ∷ BioSequence RNA) = rna == rna^.complement.complement
 
-prop_transcribe_twice_DNA (dna ∷ DNAseq) = dna == dna^.transcribe.transcribe
+prop_transcribe_twice_DNA (dna ∷ BioSequence DNA) = dna == dna^.transcribe.transcribe
 
 --prop_transcribe_twice_DNA (rna ∷ RNAseq) = rna == rna^.transcribe.transcribe
 
