packages feed

cobot-0.1.1.7: src/Bio/Chain.hs

{-# LANGUAGE TupleSections #-}
module Bio.Chain
    ( ChainLike (..)
    , Chain
    , chain, fromList
    , (!), (//)
    ) where

import           Control.Lens
import           Data.Array      (Array, Ix, array, listArray, (!), (//))
import qualified Data.Array      as A (assocs, bounds)
import           Data.Array.Base (unsafeAt)
import qualified Data.Vector     as V

type Chain i a = Array i a

-- | Construct new chain from list
--
chain :: Ix i => (i, i) -> [(i, a)] -> Chain i a
chain = array

-- | Construct new int-labeled chain from list
--
fromList :: [a] -> Chain Int a
fromList lst = listArray (0, length lst - 1) lst

-- | Chain-like sequence, by default it is an array or a list
--
class (Ixed m, Enum (Index m)) => ChainLike m where
    bounds       :: m -> (Index m, Index m)
    assocs       :: m -> [(Index m, IxValue m)]
    modify       :: Index m -> (IxValue m -> IxValue m) -> m -> m
    modifyBefore :: Index m -> (IxValue m -> IxValue m) -> m -> m
    modifyAfter  :: Index m -> (IxValue m -> IxValue m) -> m -> m

    unsafeRead   :: m -> Index m -> IxValue m
    unsafeRead ch i = ch ^?! ix i

instance ChainLike [a] where
    bounds = (0,) . pred . length

    assocs  = zip [0..]

    modify       _ _ []     = []
    modify       0 f (x:xs) = f x:xs
    modify       i f (x:xs) = x:modify (i - 1) f xs

    modifyBefore i f lst = (f <$> take i lst) ++ drop i lst
    modifyAfter  i f lst = take (i + 1) lst ++ (f <$> drop (i + 1) lst)

    unsafeRead = (!!)

instance (Ix i, Enum i) => ChainLike (Array i a) where
    bounds = A.bounds

    assocs = A.assocs

    modify       i f ar = ar // [(i, f (ar ! i))]

    modifyBefore i f ar = let (mi, _) = bounds ar
                          in ar // [(j, f (ar ! j)) | j <- [mi .. pred i]]
    modifyAfter  i f ar = let (_, ma) = bounds ar
                          in ar // [(j, f (ar ! j)) | j <- [succ i .. ma]]

    {-# INLINE unsafeRead #-}
    unsafeRead = unsafeReadArray

instance ChainLike (V.Vector a) where
    bounds v = (0, V.length v - 1)

    assocs = zip [0..] . V.toList

    modify i f ar = ar V.// [(i, f (ar V.! i))]

    modifyBefore i f ar = fmap f before <> after
      where
        (before, after) = V.splitAt i ar

    modifyAfter i f ar = before <> fmap f after
      where
        (before, after) = V.splitAt (i + 1) ar

    {-# INLINE unsafeRead #-}
    unsafeRead = V.unsafeIndex 


class (Ixed m) => UnsafeReadArray m where
    unsafeReadArray :: m -> Index m -> IxValue m

instance (Ix i, Enum i) => UnsafeReadArray (Array i a) where
    {-# INLINE unsafeReadArray #-}
    unsafeReadArray = (!)

instance {-# OVERLAPPING #-} UnsafeReadArray (Array Int a) where
    {-# INLINE unsafeReadArray #-}
    unsafeReadArray = unsafeAt