diff --git a/regex-do.cabal b/regex-do.cabal
--- a/regex-do.cabal
+++ b/regex-do.cabal
@@ -1,5 +1,5 @@
 name:                regex-do
-version:             2.0
+version:             2.1
 synopsis:            PCRE wrapper
 description:         format, search, replace (String | ByteString) with PCRE regex. Utf8-safe
 author:              Imants Cekusins
@@ -23,12 +23,14 @@
           Text.Regex.Do.Pcre.Replace
           Text.Regex.Do.Split
           Text.Regex.Do.Format
-          Text.Regex.Do.TypeDo
-          Text.Regex.Do.TypeRegex
+          Text.Regex.Do.Type.Do
+          Text.Regex.Do.Type.Reexport
           Text.Regex.Do.Convert
           Text.Regex.Do.Pad
           Text.Regex.Do.Pcre.MatchSame
           Text.Regex.Do.Pcre.ReplaceOpen
+          Text.Regex.Do.Type.Extract
+          Text.Regex.Do.Type.Regex_
   other-modules:
           Text.Regex.Do.Pcre.Matchf
           Text.Regex.Do.Pcre.Result
diff --git a/src/Text/Regex/Do/Convert.hs b/src/Text/Regex/Do/Convert.hs
--- a/src/Text/Regex/Do/Convert.hs
+++ b/src/Text/Regex/Do/Convert.hs
@@ -3,7 +3,12 @@
 import qualified Data.Text.Encoding as E
 import qualified Data.Text as T
 import Data.ByteString as B
+import Text.Regex.Do.Type.Do
+import Text.Regex.Base.RegexLike as R
+import Data.Array as A
+import Prelude as P
 
+
 -- | both Ascii and Utf8
 toByteString::String -> ByteString
 toByteString = E.encodeUtf8 . T.pack
@@ -11,3 +16,15 @@
 -- | both Ascii and Utf8
 toString::ByteString -> String
 toString = T.unpack . E.decodeUtf8
+
+
+
+class ToArray a where
+    toArray::a -> MatchArray
+
+instance ToArray MatchArray where
+    toArray = id
+
+instance ToArray [PosLen] where
+    toArray [] = listArray (0,0) []
+    toArray lpl0 = listArray (1, P.length lpl0) lpl0
diff --git a/src/Text/Regex/Do/Format.hs b/src/Text/Regex/Do/Format.hs
--- a/src/Text/Regex/Do/Format.hs
+++ b/src/Text/Regex/Do/Format.hs
@@ -2,7 +2,7 @@
     (Format(..)) where
 
 import Prelude as P
-import Text.Regex.Do.TypeDo
+import Text.Regex.Do.Type.Do
 import Text.Regex.Do.Split as S (replace)
 import Text.Regex.Do.Convert
 
diff --git a/src/Text/Regex/Do/Pcre/Match.hs b/src/Text/Regex/Do/Pcre/Match.hs
--- a/src/Text/Regex/Do/Pcre/Match.hs
+++ b/src/Text/Regex/Do/Pcre/Match.hs
@@ -5,11 +5,12 @@
     makeRegexOpts) where
 
 import qualified Text.Regex.Base.RegexLike as R hiding (makeRegex)
-import Text.Regex.Do.TypeDo
+import Text.Regex.Do.Type.Do
 import Text.Regex.Do.Pcre.Option as O
-import Text.Regex.Do.TypeRegex
+import Text.Regex.Do.Type.Reexport
 import Text.Regex.Do.Pcre.Matchf as F
 import Text.Regex.PCRE.Wrap()
+import Text.Regex.Do.Type.Regex_
 
 
 {- | 'match' covers all result types
diff --git a/src/Text/Regex/Do/Pcre/MatchSame.hs b/src/Text/Regex/Do/Pcre/MatchSame.hs
--- a/src/Text/Regex/Do/Pcre/MatchSame.hs
+++ b/src/Text/Regex/Do/Pcre/MatchSame.hs
@@ -1,6 +1,6 @@
 module Text.Regex.Do.Pcre.MatchSame where
 
-import Text.Regex.Do.TypeDo
+import Text.Regex.Do.Type.Do
 import Text.Regex.PCRE.Wrap()
 import Text.Regex.Do.Pcre.Match
 import Data.ByteString
diff --git a/src/Text/Regex/Do/Pcre/Matchf.hs b/src/Text/Regex/Do/Pcre/Matchf.hs
--- a/src/Text/Regex/Do/Pcre/Matchf.hs
+++ b/src/Text/Regex/Do/Pcre/Matchf.hs
@@ -1,10 +1,11 @@
 -- | __internal__ module, exposed only to show the instances
 module Text.Regex.Do.Pcre.Matchf where
 
-import Text.Regex.Do.TypeDo
-import Text.Regex.Do.TypeRegex
+import Text.Regex.Do.Type.Do
+import Text.Regex.Do.Type.Reexport
 import qualified Text.Regex.Do.Pcre.Result as R
 import qualified Text.Regex.Base.RegexLike as R hiding (makeRegex)
+import Text.Regex.Do.Type.Regex_
 
 
 class (Rx_ a b, Functor f) => Matchf f a b where
diff --git a/src/Text/Regex/Do/Pcre/Replace.hs b/src/Text/Regex/Do/Pcre/Replace.hs
--- a/src/Text/Regex/Do/Pcre/Replace.hs
+++ b/src/Text/Regex/Do/Pcre/Replace.hs
@@ -7,16 +7,17 @@
 import Data.ByteString as B
 import qualified Text.Regex.Do.Pcre.Option as O
 import Text.Regex.Do.Pcre.Match as M
-import Text.Regex.Do.TypeDo
-import Text.Regex.Do.TypeRegex
+import Text.Regex.Do.Type.Do
+import Text.Regex.Do.Type.Reexport
 import Text.Regex.Do.Pcre.Matchf
 import qualified Text.Regex.Do.Pcre.ReplaceOpen as O
 import Text.Regex.Do.Convert
-
+import Text.Regex.Do.Type.Regex_
+import Text.Regex.Do.Type.Extract
 
 
 {- | == dynamic group replace
-   custom replacer fn returns replacement value
+   custom replacer fn returns replacement value. See 'O.defaultReplacer'
 
    >>> replacer::GroupReplacer String
        replacer = defaultReplacer 1 tweak1
@@ -56,6 +57,7 @@
           p1 = addOpt p0 opt1
 
 
+-- | implementation detail for the curious
 class ReplaceCase_ r a where
     replace_::[ReplaceCase] -> Pattern Regex -> r a -> Body a -> a
 
@@ -84,7 +86,7 @@
 
 
 vanilla_replace::(O.ReplaceOpen [] r, O.ReplaceOpen Maybe r,
-    O.Extract' a,Rx_ a a,Opt_ a) =>
+    Extract' a,Rx_ a a,Opt_ a) =>
         [ReplaceCase] -> Pattern Regex -> r a -> Body a -> a
 vanilla_replace case0 p0 r0 b0 =
    let ma1 = marray_ p0 b0::Maybe MatchArray
diff --git a/src/Text/Regex/Do/Pcre/ReplaceOpen.hs b/src/Text/Regex/Do/Pcre/ReplaceOpen.hs
--- a/src/Text/Regex/Do/Pcre/ReplaceOpen.hs
+++ b/src/Text/Regex/Do/Pcre/ReplaceOpen.hs
@@ -7,15 +7,13 @@
 
     "Data.Text" instance already works
 
-    >>> replace (Just $ toArray [(4,3)]) (Replacement "4567") (Body "abc 123 def"::Body Text)
+    >>> replace (Just [(4,3)::PosLen]) (Replacement "4567") (Body "abc 123 def"::Body Text)
 
     "abc 4567 def"
 
     'GroupReplacer' can be used too     -}
 module Text.Regex.Do.Pcre.ReplaceOpen
     (ReplaceOpen(..),
-    toArray,
-    Extract'(..),
     defaultReplacer,
     getGroup,
     replaceMatch
@@ -25,48 +23,27 @@
 import Text.Regex.Base.RegexLike as R
 import Data.Array as A
 import Prelude as P
-import Data.ByteString as B
-import Text.Regex.Do.TypeDo
+import Text.Regex.Do.Type.Do
 import Text.Regex.Do.Pcre.Result as R
-import Data.Text as T
-
-
-toArray::[PosLen] -> MatchArray
-toArray [] = listArray (0,0) []
-toArray lpl0 = listArray (1, P.length lpl0) lpl0
-
-
-{- | see String, ByteString instances for implementation examples
-
-    see "Text.Regex.Base.RegexLike" for 'Extract' detail        -}
-class Extract a => Extract' a where
-   concat'::[a] -> a
-   len'::a -> Int
-
-
-prefix::Extract a => PosLen -> a -> a
-prefix pl0 = before $ fst pl0
-
-suffix::Extract a => PosLen -> a -> a
-suffix pl0 = after (pos1 + len1)
-  where pos1 = fst pl0
-        len1 = snd pl0
+import Text.Regex.Do.Convert
+import Text.Regex.Do.Type.Extract
 
 
 class ReplaceOpen f r where
-   replace::Extract' a => f MatchArray -> r a -> Body a -> a
+   replace::(Extract' a, ToArray arr) =>
+        f arr -> r a -> Body a -> a
 
 
 instance ReplaceOpen Maybe Replacement where
    replace Nothing (Replacement repl0) (Body b0) = b0
    replace (Just ma0) (Replacement repl0) (Body b0) = firstGroup lpl1 (repl0, b0)
-        where lpl1 = A.elems ma0
+        where lpl1 = A.elems $ toArray ma0
 
 
 instance ReplaceOpen [] Replacement where
    replace [] _ (Body b0) = b0
    replace ma0 (Replacement repl0) (Body b0) =
-      let lpl1 = R.poslen ma0::[[PosLen]]
+      let lpl1 = R.poslen $ toArray <$> ma0::[[PosLen]]
           foldFn1 lpl1 acc1 = firstGroup lpl1 (repl0,acc1)
       in P.foldr foldFn1 b0 lpl1
 
@@ -78,14 +55,14 @@
                                   acc = b0,
                                   pos_adj = 0
                                 }
-            in acc $ repl0 ma0 a1
+            in acc $ repl0 (toArray ma0) a1
 
 
 instance ReplaceOpen [] GroupReplacer where
    replace [] _ (Body b0) = b0
    replace ma0 (GroupReplacer repl0) (Body b0) =
         let acc1 = ReplaceAcc { acc = b0, pos_adj = 0 }
-        in acc $ P.foldl (flip repl0) acc1 ma0
+        in acc $ P.foldl (flip repl0) acc1 $ toArray <$> ma0
 
 
 firstGroup::Extract' a =>
@@ -96,26 +73,6 @@
                     pos_adj = 0
                     }
 
-
-instance Extract' String where
-   concat' = P.concat
-   len' = P.length
-
-
-instance Extract' B.ByteString where
-   concat' = B.concat
-   len' = B.length
-
-
-instance Extract Text where
-    before = T.take
-    after = T.drop
-    empty = T.empty
-
-
-instance Extract' Text where
-    concat' = T.concat
-    len' = T.length
 
 
 --  dynamic
diff --git a/src/Text/Regex/Do/Pcre/Result.hs b/src/Text/Regex/Do/Pcre/Result.hs
--- a/src/Text/Regex/Do/Pcre/Result.hs
+++ b/src/Text/Regex/Do/Pcre/Result.hs
@@ -2,7 +2,7 @@
 
 import qualified Data.Array as A(elems)
 import Text.Regex.Base.RegexLike as R
-import Text.Regex.Do.TypeDo
+import Text.Regex.Do.Type.Do
 
 -- | match offset, length
 poslen::Functor f =>
diff --git a/src/Text/Regex/Do/Split.hs b/src/Text/Regex/Do/Split.hs
--- a/src/Text/Regex/Do/Split.hs
+++ b/src/Text/Regex/Do/Split.hs
@@ -9,7 +9,7 @@
     KeepNeedle(..)) where
 
 import qualified Data.ByteString.Search as S
-import Text.Regex.Do.TypeDo hiding (replace)
+import Text.Regex.Do.Type.Do hiding (replace)
 import Data.ByteString as B hiding (break, breakEnd, split)
 import qualified Data.ByteString.Lazy as L
 import Prelude hiding (break)
diff --git a/src/Text/Regex/Do/Trim.hs b/src/Text/Regex/Do/Trim.hs
--- a/src/Text/Regex/Do/Trim.hs
+++ b/src/Text/Regex/Do/Trim.hs
@@ -1,6 +1,6 @@
 module Text.Regex.Do.Trim where
 
-import Text.Regex.Do.TypeDo
+import Text.Regex.Do.Type.Do
 import Data.Char(isSpace)
 import qualified Data.ByteString as B
 import Text.Regex.Do.Convert
diff --git a/src/Text/Regex/Do/Type/Do.hs b/src/Text/Regex/Do/Type/Do.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Regex/Do/Type/Do.hs
@@ -0,0 +1,35 @@
+module Text.Regex.Do.Type.Do where
+
+import Text.Regex.Base.RegexLike as R
+import Text.Regex.Do.Type.Reexport
+
+
+-- | see "Text.Regex.Do.Pcre.ReplaceOpen" 'defaultReplacer' for example implementation
+newtype GroupReplacer b = GroupReplacer (MatchArray -> ReplaceAcc b -> ReplaceAcc b) -- MatchArray -> acc -> acc
+
+
+data ReplaceAcc b = ReplaceAcc {
+    acc::b,   -- ^ content with some replacements made
+    pos_adj::Int    {- ^ position adjustment: group replacement length may differ from replaced text length -}
+    }
+
+
+-- | Needle
+data Pattern a = Pattern a  deriving (Functor)          -- Bs, String, RegexPcre
+
+-- | Haystack
+data Body b = Body b deriving (Functor)                -- Bs, String
+
+data Replacement r = Replacement r deriving (Functor)     --    Bs, String
+
+-- | Offset, Length
+type PosLen = (MatchOffset, MatchLength)
+
+
+data ReplaceCase = Once     -- ^ may be omitted
+                | All       -- ^ if both Once and All are passed, All prevails
+                | Utf8
+                | Multiline deriving Eq
+
+
+type Opt_ a = R.RegexMaker Regex CompOption ExecOption a
diff --git a/src/Text/Regex/Do/Type/Extract.hs b/src/Text/Regex/Do/Type/Extract.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Regex/Do/Type/Extract.hs
@@ -0,0 +1,45 @@
+module Text.Regex.Do.Type.Extract where
+
+import Text.Regex.Base.RegexLike as R
+import Prelude as P
+import Data.ByteString as B
+import Data.Text as T
+import Text.Regex.Do.Type.Do
+
+
+{- | see String, ByteString instances for implementation examples
+
+    see "Text.Regex.Base.RegexLike" for 'Extract' detail        -}
+class Extract a => Extract' a where
+   concat'::[a] -> a
+   len'::a -> Int
+
+
+instance Extract' String where
+   concat' = P.concat
+   len' = P.length
+
+
+instance Extract' B.ByteString where
+   concat' = B.concat
+   len' = B.length
+
+
+instance Extract Text where
+    before = T.take
+    after = T.drop
+    empty = T.empty
+
+
+instance Extract' Text where
+    concat' = T.concat
+    len' = T.length
+
+
+prefix::Extract a => PosLen -> a -> a
+prefix pl0 = before $ fst pl0
+
+suffix::Extract a => PosLen -> a -> a
+suffix pl0 = after (pos1 + len1)
+  where pos1 = fst pl0
+        len1 = snd pl0
diff --git a/src/Text/Regex/Do/Type/Reexport.hs b/src/Text/Regex/Do/Type/Reexport.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Regex/Do/Type/Reexport.hs
@@ -0,0 +1,15 @@
+-- | reexport common types from "Text.Regex.PCRE"
+module Text.Regex.Do.Type.Reexport (
+    W.Regex(..),
+    R.MatchArray(..),
+    W.CompOption(..),
+    W.ExecOption()
+    )   where
+
+import Text.Regex.PCRE.ByteString as B (Regex)
+import Text.Regex.PCRE.String as S (Regex)
+import Text.Regex.Base.RegexLike as R (MatchArray)
+import Text.Regex.PCRE.Wrap as W
+
+type RegexB = B.Regex
+type RegexS = S.Regex
diff --git a/src/Text/Regex/Do/Type/Regex_.hs b/src/Text/Regex/Do/Type/Regex_.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Regex/Do/Type/Regex_.hs
@@ -0,0 +1,22 @@
+module Text.Regex.Do.Type.Regex_ where
+
+import Text.Regex.Base.RegexLike as R
+import Text.Regex.Do.Type.Reexport
+import Data.ByteString
+import Text.Regex.Do.Type.Do
+
+
+class Regex_ a where
+   r_::Pattern a -> Regex
+
+instance Regex_ ByteString where
+   r_ (Pattern p0) = R.makeRegex p0
+
+instance Regex_ String where
+   r_ (Pattern p0) = R.makeRegex p0
+
+instance Regex_ Regex where
+   r_ (Pattern p0) = p0
+
+
+type Rx_ a b = (Regex_ a, R.Extract b, R.RegexLike Regex b)
diff --git a/src/Text/Regex/Do/TypeDo.hs b/src/Text/Regex/Do/TypeDo.hs
deleted file mode 100644
--- a/src/Text/Regex/Do/TypeDo.hs
+++ /dev/null
@@ -1,51 +0,0 @@
-module Text.Regex.Do.TypeDo where
-
-import Text.Regex.Base.RegexLike as R
-import Text.Regex.Do.TypeRegex
-import Data.ByteString
-
-
--- pcre
-newtype GroupReplacer b = GroupReplacer (MatchArray -> ReplaceAcc b -> ReplaceAcc b) -- MatchArray -> acc -> acc
-
-
-data ReplaceAcc b = ReplaceAcc {
-    acc::b,   -- ^ content with some replacements made
-    pos_adj::Int    {- ^ position adjustment: group replacement length may differ from replaced text length -}
-    }
-
-
--- | Needle
-data Pattern a = Pattern a  deriving (Functor)          -- Bs, String, RegexPcre
-
--- | Haystack
-data Body b = Body b deriving (Functor)                -- Bs, String
-
-data Replacement r = Replacement r deriving (Functor)     --    Bs, String
-
--- | Offset, Length
-type PosLen = (MatchOffset, MatchLength)
-
-
-data ReplaceCase = Once     -- ^ may be omitted
-                | All       -- ^ if both Once and All are passed, All prevails
-                | Utf8
-                | Multiline deriving Eq
-
-
-
-type Opt_ a = R.RegexMaker Regex CompOption ExecOption a
-type Rx_ a b = (Regex_ a, R.Extract b, R.RegexLike Regex b)
-
-
-class Regex_ a where
-   r_::Pattern a -> Regex
-
-instance Regex_ ByteString where
-   r_ (Pattern p0) = R.makeRegex p0
-
-instance Regex_ String where
-   r_ (Pattern p0) = R.makeRegex p0
-
-instance Regex_ Regex where
-   r_ (Pattern p0) = p0
diff --git a/src/Text/Regex/Do/TypeRegex.hs b/src/Text/Regex/Do/TypeRegex.hs
deleted file mode 100644
--- a/src/Text/Regex/Do/TypeRegex.hs
+++ /dev/null
@@ -1,15 +0,0 @@
--- | reexport common types from "Text.Regex.PCRE"
-module Text.Regex.Do.TypeRegex (
-    W.Regex(..),
-    R.MatchArray(..),
-    W.CompOption(..),
-    W.ExecOption()
-    )   where
-
-import Text.Regex.PCRE.ByteString as B (Regex)
-import Text.Regex.PCRE.String as S (Regex)
-import Text.Regex.Base.RegexLike as R (MatchArray)
-import Text.Regex.PCRE.Wrap as W
-
-type RegexB = B.Regex
-type RegexS = S.Regex
diff --git a/test/TestRegex/TestFormat.hs b/test/TestRegex/TestFormat.hs
--- a/test/TestRegex/TestFormat.hs
+++ b/test/TestRegex/TestFormat.hs
@@ -13,8 +13,10 @@
             format "на первое {0}, на второе {0}" ([]::[String]) `shouldBe` "на первое {0}, на второе {0}"
           it "list arg 0,0" $
             format "на первое {0}, на второе {0}" ["перловка"] `shouldBe` "на первое перловка, на второе перловка"
-          it "list arg 0,1" $
+          it "list arg 0,1" $ do
             format "Polly {0} a {1}" ["gets","cracker"] `shouldBe` "Polly gets a cracker"
+            format "{10} {15} {21}" (show <$> [0..22]) `shouldBe` "10 15 21"
+            format "{ten} {пятнадцать} {vingt}" [("ten","10"), ("пятнадцать", "15"), ("vingt", "20")] `shouldBe` "10 15 20"
           it "map arg" $
             format "овчинка {a} не {b}" [("a","выделки"),("b","стоит")] `shouldBe` "овчинка выделки не стоит"
           it "pad" $ pad '-' 5 "abc" `shouldBe` "--abc"
diff --git a/test/TestRegex/TestPcre.hs b/test/TestRegex/TestPcre.hs
--- a/test/TestRegex/TestPcre.hs
+++ b/test/TestRegex/TestPcre.hs
@@ -1,7 +1,7 @@
 module TestRegex.TestPcre where
 
 import Test.Hspec
-import Text.Regex.Do.TypeDo as M
+import Text.Regex.Do.Type.Do as M
 import Text.Regex.Do.Pcre.Match as M
 import Text.Regex.Do.Convert
 import Data.ByteString
diff --git a/test/TestRegex/TestReplace.hs b/test/TestRegex/TestReplace.hs
--- a/test/TestRegex/TestReplace.hs
+++ b/test/TestRegex/TestReplace.hs
@@ -2,7 +2,7 @@
 module TestRegex.TestReplace where
 
 import Test.Hspec
-import Text.Regex.Do.TypeDo
+import Text.Regex.Do.Type.Do
 
 import Text.Regex.Do.Pcre.Replace as R
 import Text.Regex.Do.Pcre.ReplaceOpen hiding (replace)
diff --git a/test/TestRegex/TestSplit.hs b/test/TestRegex/TestSplit.hs
--- a/test/TestRegex/TestSplit.hs
+++ b/test/TestRegex/TestSplit.hs
@@ -3,7 +3,7 @@
 import Prelude hiding(break)
 import Test.Hspec
 import Control.Exception (evaluate)
-import Text.Regex.Do.TypeDo
+import Text.Regex.Do.Type.Do
 import Text.Regex.Do.Split as S
 import qualified Data.ByteString as B
 import Text.Regex.Do.Convert
