diff --git a/src/Yi/Rope.hs b/src/Yi/Rope.hs
--- a/src/Yi/Rope.hs
+++ b/src/Yi/Rope.hs
@@ -62,9 +62,11 @@
 import           Control.DeepSeq
 import           Data.Binary
 import           Data.Char (isSpace)
+import           Data.Default
 import qualified Data.FingerTree as T
 import           Data.FingerTree hiding (null, empty, reverse, split)
 import qualified Data.List as L (foldl')
+import           Data.Maybe
 import           Data.Monoid
 import           Data.String (IsString(..))
 import qualified Data.Text as TX
@@ -151,6 +153,9 @@
 instance Ord YiString where
   compare x y = toText x `compare` toText y
 
+instance Default YiString where
+  def = mempty
+
 (-|) :: YiChunk -> FingerTree Size YiChunk -> FingerTree Size YiChunk
 b -| t | chunkSize b == 0 = t
        | otherwise        = b <| t
@@ -264,8 +269,24 @@
 countNewLines = lineIndex . measure . fromRope
 
 -- | Append two 'YiString's.
+--
+-- We take the extra time to optimise this append for many small
+-- insertions. With naive append of the inner fingertree with 'T.><',
+-- it is often the case that we end up with a large collection of tiny
+-- chunks. This function instead tries to join the underlying trees at
+-- outermost chunks up to 'defaultChunkSize' which while slower,
+-- should improve memory usage.
+--
+-- I suspect that this pays for itself as we'd spend more time
+-- computing over all the little chunks than few large ones anyway.
 append :: YiString -> YiString -> YiString
-append (YiString t) (YiString t') = YiString $ t T.>< t'
+append (YiString t) (YiString t') = case (viewr t, viewl t') of
+  (EmptyR, _) -> YiString t'
+  (_, EmptyL) -> YiString t
+  (ts :> Chunk l x, Chunk l' x' :< ts') ->
+    let len = l + l' in case compare len defaultChunkSize of
+      GT -> YiString (t <> t')
+      _ -> YiString (ts |- Chunk len (x <> x') <> ts')
 
 -- | Concat a list of 'YiString's.
 concat :: [YiString] -> YiString
@@ -334,10 +355,12 @@
 
 -- | Takes the first n given characters.
 take :: Int -> YiString -> YiString
+take 1 = maybe def Yi.Rope.singleton . Yi.Rope.head
 take n = fst . Yi.Rope.splitAt n
 
 -- | Drops the first n characters.
 drop :: Int -> YiString -> YiString
+drop 1 = fromMaybe def . Yi.Rope.tail
 drop n = snd . Yi.Rope.splitAt n
 
 -- | The usual 'Prelude.dropWhile' optimised for 'YiString's.
@@ -444,10 +467,10 @@
 -- pre-process the list.
 intercalate :: YiString -> [YiString] -> YiString
 intercalate _ [] = mempty
-intercalate (YiString t') ts = YiString $ t' >< go ts
+intercalate (YiString t') (YiString s:ss) = YiString $ s >< go ss
   where
     go []                = mempty
-    go (YiString t : ts') = t >< t' >< go ts'
+    go (YiString t : ts') = t' >< t >< go ts'
 
 -- | Intersperses the given character between the 'YiString's. This is
 -- useful when you have a bunch of strings you just want to separate
diff --git a/test/Yi/RopeSpec.hs b/test/Yi/RopeSpec.hs
--- a/test/Yi/RopeSpec.hs
+++ b/test/Yi/RopeSpec.hs
@@ -101,3 +101,6 @@
       in (R.foldl' f 0 . R.fromText) t `shouldBe` T.foldl' f 0 t
     prop "R.replicate ~ T.replicate" $ \n ->
       R.replicate n `isLikeT` T.replicate n
+    prop "R.intercalate ~ T.intercalate" $ \t ts ->
+      R.toText (R.intercalate (R.fromText t) (R.fromText <$> ts))
+      `shouldBe` T.intercalate t ts
diff --git a/yi-rope.cabal b/yi-rope.cabal
--- a/yi-rope.cabal
+++ b/yi-rope.cabal
@@ -1,5 +1,5 @@
 name:                yi-rope
-version:             0.4.0.1
+version:             0.4.1.0
 synopsis:            A rope data structure used by Yi
 description:         A rope data structure used by Yi
 license:             GPL-2
@@ -22,6 +22,7 @@
   build-depends:
       base >=4.5 && <5
     , binary
+    , data-default
     , deepseq
     , fingertree
     , text
