diff --git a/Codec/Binary/UTF8/String.hs b/Codec/Binary/UTF8/String.hs
--- a/Codec/Binary/UTF8/String.hs
+++ b/Codec/Binary/UTF8/String.hs
@@ -16,9 +16,12 @@
     , decode
     , encodeString
     , decodeString
+    
+    , isUTF8Encoded
+    , utf8Encode
   ) where
 
-import Data.Word        (Word8)
+import Data.Word        (Word8,Word32)
 import Data.Bits        ((.|.),(.&.),shiftL,shiftR)
 import Data.Char        (chr,ord)
 
@@ -94,4 +97,61 @@
                                $ shiftL acc 6 .|. fromEnum (r .&. 0x3f)
 
         aux _ rs     _ = replacement_character : decode rs
+
+
+-- | @utf8Encode str@ is a convenience function; checks to see if
+-- @str@ isn't UTF-8 encoded before doing so. Sometimes useful, but
+-- you are better off keeping track of the encoding so as to avoid
+-- the cost of checking.
+utf8Encode :: String -> String
+utf8Encode str
+ | isUTF8Encoded str = str
+ | otherwise         = encodeString str
+
+
+-- | @isUTF8Encoded str@ tries to recognize input string as being in UTF-8 form.
+isUTF8Encoded :: String -> Bool
+isUTF8Encoded [] = True
+isUTF8Encoded (x:xs) = 
+  case ox of
+    _ | ox < 0x80  -> isUTF8Encoded xs
+      | ox > 0xff  -> False
+      | ox < 0xc0  -> False
+      | ox < 0xe0  -> check1
+      | ox < 0xf0  -> check_byte 2 0xf 0
+      | ox < 0xf8  -> check_byte 3 0x7  0x10000
+      | ox < 0xfc  -> check_byte 4 0x3  0x200000
+      | ox < 0xfe  -> check_byte 5 0x1  0x4000000
+      | otherwise  -> False
+ where
+   ox = toW32 x
+   
+   toW32 :: Char -> Word32
+   toW32 ch = fromIntegral (fromEnum ch)
+
+   check1 = 
+    case xs of
+     [] -> False
+     c1 : ds 
+      | oc .&. 0xc0 /= 0x80 || d < 0x000080 -> False
+      | otherwise -> isUTF8Encoded ds
+      where
+       oc = toW32 c1
+       d = ((ox .&. 0x1f) `shiftL` 6) .|.  (oc .&. 0x3f)
+
+   check_byte :: Int -> Word32 -> Word32 -> Bool
+   check_byte i mask overlong = aux i xs (ox .&. mask)
+      where
+        aux 0 rs acc
+         | overlong <= acc && 
+	   acc <= 0x10ffff &&
+           (acc < 0xd800 || 0xdfff < acc) &&
+           (acc < 0xfffe || 0xffff < acc) = isUTF8Encoded rs
+         | otherwise = False
+
+        aux n (r:rs) acc
+         | toW32 r .&. 0xc0 == 0x80 = 
+	    aux (n-1) rs  (acc `shiftL` 6 .|. (toW32 r .&. 0x3f))
+
+        aux _ _  _ = False
 
diff --git a/Data/String/UTF8.hs b/Data/String/UTF8.hs
--- a/Data/String/UTF8.hs
+++ b/Data/String/UTF8.hs
@@ -1,5 +1,4 @@
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# OPTIONS_GHC -fallow-undecidable-instances #-}
+{-# LANGUAGE MultiParamTypeClasses, UndecidableInstances #-}
 module Data.String.UTF8
   ( -- * Representation
     UTF8
diff --git a/System/Environment/UTF8.hs b/System/Environment/UTF8.hs
new file mode 100644
--- /dev/null
+++ b/System/Environment/UTF8.hs
@@ -0,0 +1,25 @@
+module System.Environment.UTF8
+  (getArgs, getProgName, getEnv, withArgs, withProgName, getEnvironment)
+  where
+
+import Codec.Binary.UTF8.String (decodeString)
+import qualified System.Environment as Sys
+
+getArgs :: IO [String]
+getArgs = map decodeString `fmap` Sys.getArgs
+
+getProgName :: IO String
+getProgName = decodeString `fmap` Sys.getProgName
+
+getEnv :: String -> IO String
+getEnv x = decodeString `fmap` Sys.getEnv x
+
+withArgs :: [String] -> IO a -> IO a
+withArgs = Sys.withArgs
+
+withProgName :: String -> IO a -> IO a
+withProgName = Sys.withProgName
+
+getEnvironment :: IO [(String,String)]
+getEnvironment = map f `fmap` Sys.getEnvironment
+  where f (a,b) = (decodeString a, decodeString b)
diff --git a/utf8-string.cabal b/utf8-string.cabal
--- a/utf8-string.cabal
+++ b/utf8-string.cabal
@@ -1,5 +1,5 @@
 Name:               utf8-string
-Version:            0.3.4
+Version:            0.3.5
 Author:             Eric Mertens
 Maintainer:         emertens@galois.com
 License:            BSD3
@@ -29,6 +29,7 @@
   Exposed-modules:    Codec.Binary.UTF8.String
                       Codec.Binary.UTF8.Generic
                       System.IO.UTF8
+                      System.Environment.UTF8
                       Data.String.UTF8
                       Data.ByteString.UTF8
                       Data.ByteString.Lazy.UTF8
