{-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Data.Strict.Vector.Lens ( toVectorOf , vector , forced , sliced , ordinals ) where import Control.Lens import Control.Lens.Internal.List (ordinalNub) import Data.Vector.Generic.Lens (vectorTraverse) import Data.Monoid (Endo) import qualified Data.Strict.Vector as V import Data.Strict.Vector (Vector) #if !MIN_VERSION_lens(5,0,0) instance FunctorWithIndex Int Vector where imap = V.imap {-# INLINE imap #-} instance FoldableWithIndex Int Vector where ifoldr = V.ifoldr {-# INLINE ifoldr #-} ifoldl = V.ifoldl . flip {-# INLINE ifoldl #-} ifoldr' = V.ifoldr' {-# INLINE ifoldr' #-} ifoldl' = V.ifoldl' . flip {-# INLINE ifoldl' #-} instance TraversableWithIndex Int Vector where itraverse f v = let !n = V.length v in V.fromListN n <$> itraverse f (V.toList v) {-# INLINE itraverse #-} #endif type instance Index (Vector a) = Int type instance IxValue (Vector a) = a instance Ixed (Vector a) where -- This is slightly different from lens' definition to make our ixTest work. -- Unlike Sequence, since the element is stored inside a primitive array the -- only way to get it is via a primop, so we have to force-apply ($!) the -- extraction. Pattern matching on a case-expr (e.g. the result of V.!?) is -- ineffective because that still has to call the primop, so we would still -- have a thunk after pattern matching. ix i f v | 0 <= i && i < V.length v = (f $! v V.! i) <&> \a -> v V.// [(i, a)] | otherwise = pure v {-# INLINE ix #-} instance AsEmpty (Vector a) where _Empty = nearly V.empty V.null {-# INLINE _Empty #-} instance Each (Vector a) (Vector b) a b where each = vectorTraverse {-# INLINE each #-} instance (t ~ Vector a') => Rewrapped (Vector a) t instance Wrapped (Vector a) where type Unwrapped (Vector a) = [a] _Wrapped' = iso V.toList V.fromList {-# INLINE _Wrapped' #-} instance Cons (Vector a) (Vector b) a b where _Cons = prism (uncurry V.cons) $ \v -> if V.null v then Left V.empty else Right (V.unsafeHead v, V.unsafeTail v) {-# INLINE _Cons #-} instance Snoc (Vector a) (Vector b) a b where _Snoc = prism (uncurry V.snoc) $ \v -> if V.null v then Left V.empty else Right (V.unsafeInit v, V.unsafeLast v) {-# INLINE _Snoc #-} instance Reversing (Vector a) where reversing = V.reverse -- | Analogous to 'Data.Vector.Lens.sliced'. sliced :: Int -- ^ @i@ starting index -> Int -- ^ @n@ length -> Lens' (Vector a) (Vector a) sliced i n f v = f (V.slice i n v) <&> \ v0 -> v V.// zip [i..i+n-1] (V.toList v0) {-# INLINE sliced #-} -- | Analogous to 'Data.Vector.Lens.toVectorOf'. toVectorOf :: Getting (Endo [a]) s a -> s -> Vector a toVectorOf l s = V.fromList (toListOf l s) {-# INLINE toVectorOf #-} -- | Analogous to 'Data.Vector.Lens.vector'. vector :: Iso [a] [b] (Vector a) (Vector b) vector = iso V.fromList V.toList {-# INLINE vector #-} -- | Analogous to 'Data.Vector.Lens.forced'. forced :: Iso (Vector a) (Vector b) (Vector a) (Vector b) forced = iso V.force V.force {-# INLINE forced #-} -- | Analogous to 'Data.Vector.Lens.ordinals'. ordinals :: [Int] -> IndexedTraversal' Int (Vector a) a ordinals is f v = fmap (v V.//) $ traverse (\i -> (,) i <$> indexed f i (v V.! i)) $ ordinalNub (length v) is {-# INLINE ordinals #-}