diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,5 @@
 Copyright (c) 2012-2015, Computational Linguistics Ltd.
-              2012-2019, Mikolaj Konarski
+              2012-2020, Mikolaj Konarski and others (see git commits)
 
 All rights reserved.
 
diff --git a/NLP/Minimorph/English.hs b/NLP/Minimorph/English.hs
--- a/NLP/Minimorph/English.hs
+++ b/NLP/Minimorph/English.hs
@@ -3,8 +3,10 @@
 -- |Simple default rules for English morphology
 module NLP.Minimorph.English where
 
--- Only needed for older GHC, but let's avoid CPP for this instance.
-import Data.Monoid ((<>))
+#if !(MIN_VERSION_base(4,11,0))
+  -- this is redundant starting with base-4.11 / GHC 8.4
+import Data.Semigroup
+#endif
 
 import           Data.Char (isSpace, isUpper, toLower)
 import           Data.Text (Text)
@@ -271,5 +273,8 @@
 isLetterWithInitialVowelSound = (`elem` ("aeiofhlmnrsx" :: String)) . toLower
 
 -- | Is a consonant.
+--
+--   Note that not every `Char` is either a vowel or a consonant.
+--   We consider numbers, spaces and symbols to be neither vowel or consonants
 isConsonant :: Char -> Bool
-isConsonant = not . isVowel
+isConsonant = (`elem` ("bcdfghjklmnpqrstvwxyz" :: String)) . toLower
diff --git a/NLP/Minimorph/Util.hs b/NLP/Minimorph/Util.hs
--- a/NLP/Minimorph/Util.hs
+++ b/NLP/Minimorph/Util.hs
@@ -3,18 +3,22 @@
  ( (<+>), tshow )
  where
 
--- Only needed for older GHC, but let's avoid CPP for this instance.
-import Data.Monoid ((<>))
+#if !(MIN_VERSION_base(4,11,0))
+  -- this is redundant starting with base-4.11 / GHC 8.4
+import Data.Semigroup
+#endif
 
+import qualified Data.Char as Char
 import           Data.Text (Text)
 import qualified Data.Text as T
 
 infixr 6 <+>  -- matches Monoid.<>
 -- | Separated by space unless one of them is empty (in which case just
---   the non-empty one).
+--   the non-empty one) or the first ends or the last begins with whitespace.
 (<+>) :: Text -> Text -> Text
 t1 <+> t2 | T.null t1 = t2
           | T.null t2 = t1
+          | Char.isSpace (T.last t1) || Char.isSpace (T.head t2) = t1 <> t2
           | otherwise = t1 <> " " <> t2
 
 -- | Show a value in `Text` format.
diff --git a/minimorph.cabal b/minimorph.cabal
--- a/minimorph.cabal
+++ b/minimorph.cabal
@@ -5,7 +5,7 @@
 -- PVP summary:      +-+------- breaking API changes
 --                   | | +----- minor or non-breaking API additions
 --                   | | | +--- code changes with no API change
-version:             0.2.2.0
+version:             0.3.0.0
 synopsis:            English spelling functions with an emphasis on simplicity.
 description:         A set of simplistic functions capturing the more regular
                      parts of English spelling (for generation, not parsing).
@@ -39,9 +39,10 @@
 
   build-depends:       base < 5
                ,       text >= 1.1.1
+  if !impl(ghc >= 8.0)
+    build-depends: semigroups == 0.18.*
 
   default-language:   Haskell2010
-  default-extensions: OverloadedStrings
   if impl(ghc >= 8.0)
   {
   default-extensions: MonoLocalBinds, ScopedTypeVariables, OverloadedStrings
@@ -52,6 +53,8 @@
   ghc-options:        -Wall -Wcompat -Worphans -Wincomplete-uni-patterns -Wincomplete-record-updates -Wmissing-home-modules -Widentities -Wredundant-constraints -Wpartial-fields
   ghc-options:        -Wall-missed-specialisations
   ghc-options:        -fno-ignore-asserts -fexpose-all-unfoldings -fspecialise-aggressively -fsimpl-tick-factor=200
+  } else {
+  default-extensions: CPP, OverloadedStrings
   }
 
 test-suite test-minimorph
@@ -65,8 +68,10 @@
                ,       test-framework
                ,       test-framework-hunit
                ,       text
+  if !impl(ghc >= 8.0)
+    build-depends: semigroups == 0.18.*
+
   default-language:   Haskell2010
-  default-extensions: OverloadedStrings
   if impl(ghc >= 8.0)
   {
   default-extensions: MonoLocalBinds, ScopedTypeVariables, OverloadedStrings
@@ -77,4 +82,6 @@
   ghc-options:        -Wall-missed-specialisations
   ghc-options:        -fno-ignore-asserts -fexpose-all-unfoldings -fspecialise-aggressively -fsimpl-tick-factor=200
   ghc-options:        -threaded -rtsopts
+  } else {
+  default-extensions: CPP, OverloadedStrings
   }
diff --git a/test/NLP/Minimorph/EnglishTest.hs b/test/NLP/Minimorph/EnglishTest.hs
--- a/test/NLP/Minimorph/EnglishTest.hs
+++ b/test/NLP/Minimorph/EnglishTest.hs
@@ -127,6 +127,7 @@
     , noun "thesis" "theses"
     , noun "elf"    "elves"
     , noun "ace"    "aces"
+    , noun "5y"     "5ys"
     ]
   where
     noun s p = (s,p)
