{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ViewPatterns #-}
module Bio.Sequence.Functions.Sequence
( drop
, getRange, unsafeGetRange
, length, null
, reverse
, tail
, take
, toList
, (!), (!?)
) where
import Bio.Sequence.Class (ContainsNoMarking, IsSequence (..),
markings, sequ, weights,
_sequenceInner)
import Bio.Sequence.Utilities (Range, checkRange, unsafeEither)
import Control.Lens
import Control.Monad.Except (MonadError, throwError)
import Data.Bifunctor (bimap)
import qualified Data.Foldable as F (length, null, toList)
import qualified Data.List as L (drop, take)
import Data.Maybe (fromMaybe)
import Data.Text (Text)
import Data.Tuple (swap)
import qualified Data.Vector as V (drop, reverse, take, (!?))
import Prelude hiding (drop, length, null, reverse,
tail, take)
getRange :: (IsSequence s, MonadError Text m) => s -> Range -> m [Element s]
getRange s r@(lInd, rInd) | checkRange (length s) r = pure $ L.take (rInd - lInd) $ L.drop lInd $ toList s
| otherwise = throwError "Bio.Sequence.Functions.Sequence: invalid range in getRange."
unsafeGetRange :: IsSequence s => s -> Range -> [Element s]
unsafeGetRange s = unsafeEither . getRange s
infixl 9 !
(!) :: IsSequence s => s -> Int -> Element s
(!) s = fromMaybe (error "Bio.Sequence.Functions.Sequence: index out of Sequence's length.") . (s !?)
infixl 9 !?
(!?) :: IsSequence s => s -> Int -> Maybe (Element s)
(!?) (toSequence -> s) = ((s ^. sequ) V.!?)
toList :: IsSequence s => s -> [Element s]
toList = F.toList . toSequence
length :: IsSequence s => s -> Int
length = F.length . toSequence
null :: IsSequence s => s -> Bool
null = F.null . toSequence
reverse :: IsSequence s => s -> s
reverse (toSequence -> s) = res
where
newMaxInd = length s
newSequ = V.reverse $ s ^. sequ
newMarkings = fmap (fmap $ swap . bimap ((-) newMaxInd) ((-) newMaxInd)) $ s ^. markings
newWeights = V.reverse $ s ^. weights
res = fromSequence $ _sequenceInner newSequ newMarkings newWeights
drop :: ContainsNoMarking s => Int -> s -> s
drop n (toSequence -> s) | n < 0 = error "Bio.Sequence.Functions.Sequence: drop with negative value."
| n >= length s = error "Bio.Sequence.Functions.Sequence: empty sequence as result of drop."
| otherwise = res
where
droppedSequ = V.drop n $ s ^. sequ
newWeights = V.drop n $ s ^. weights
res = fromSequence $ _sequenceInner droppedSequ mempty newWeights
take :: ContainsNoMarking s => Int -> s -> s
take n (toSequence -> s) | n < 0 = error "Bio.Sequence.Functions.Sequence: take with negative value."
| n == 0 = error "Bio.Sequence.Functions.Sequence: empty sequence as result of take."
| otherwise = res
where
takenSequ = V.take n $ s ^. sequ
newWeights = V.take n $ s ^. weights
res = fromSequence $ _sequenceInner takenSequ mempty newWeights
tail :: ContainsNoMarking s => s -> s
tail s | length s == 0 = error "Bio.Sequence.Functions.Sequence: tail from empty sequence."
| otherwise = drop 1 s