diff --git a/HsPerl5.cabal b/HsPerl5.cabal
--- a/HsPerl5.cabal
+++ b/HsPerl5.cabal
@@ -1,18 +1,29 @@
 name:               HsPerl5
-version:            0.0.1
+version:            0.0.2
 copyright:          2008 Audrey Tang
 license:            BSD3
 license-file:       LICENSE
 author:             Audrey Tang <audreyt@audreyt.org>
 maintainer:         Audrey Tang <audreyt@audreyt.org>
 synopsis:           Haskell interface to embedded Perl 5 interpreter
-description:        Haskell interface to embedded Perl 5 interpreter
+
+description:        This module provides a Haskell interface to embedded Perl 5 interpreter.
+
+                    Documentation and functionality is scarce at the moment; see test.hs for
+                    some basic usage examples.
+
+                    Eventually the entirety of Pugs.Embed.Perl5 and Pugs.Run.Perl5 will be
+                    carried into this module.
+
 stability:          experimental
 build-type:         Simple
-extensions:         ForeignFunctionInterface
+extensions:         ForeignFunctionInterface, TypeSynonymInstances,
+                    ScopedTypeVariables, FlexibleInstances,
+                    UndecidableInstances, OverlappingInstances
 exposed-modules:    Language.Perl5
 build-depends:      base
 extra-source-files: README test.hs configure
 hs-source-dirs:     src
 category:           Language
 c-sources:          p5embed.c
+includes:           p5embed.h
diff --git a/p5embed.c b/p5embed.c
--- a/p5embed.c
+++ b/p5embed.c
@@ -28,6 +28,18 @@
     return(&PL_sv_undef);
 }
 
+SV *
+perl5_sv_yes ()
+{
+    return(&PL_sv_yes);
+}
+
+SV *
+perl5_sv_no ()
+{
+    return(&PL_sv_no);
+}
+
 PerlInterpreter *
 perl5_init ( int argc, char **argv )
 {
@@ -99,36 +111,64 @@
     return my_perl;
 }
 
-SV *
-perl5_eval(char *code, int cxt)
+SV **
+perl5_eval(char *code, int len, int cxt)
 {
     dSP;
     SV* sv;
+    int count;
 
     ENTER;
     SAVETMPS;
 
-    sv = newSVpv(code, 0);
+    sv = newSVpvn(code, len);
 #ifdef SvUTF8_on
     SvUTF8_on(sv);
 #endif
-    eval_sv(sv, cxt);
+    count = eval_sv(sv, cxt);
     SvREFCNT_dec(sv);
 
+    return perl5_return_conv(count);
+}
+
+
+SV **
+perl5_return_conv (int count) {
+    SV **out;
+    int i;
+
+    dSP;
     SPAGAIN;
-    sv = POPs;
-    SvREFCNT_inc(sv);
-    PUTBACK;
 
     if (SvTRUE(ERRSV)) {
-        STRLEN n_a;
-        fprintf(stderr, "Error eval perl5: \"%s\"\n*** %s\n", code, SvPV(ERRSV,n_a));
+        Newz(42, out, 3, SV*);
+        if (SvROK(ERRSV)) {
+            out[0] = newSVsv(ERRSV);
+            out[1] = NULL;
+        }
+        else {
+            out[0] = ERRSV;
+            out[1] = ERRSV; /* for Haskell-side to read PV */
+        }
+        out[2] = NULL;
     }
+    else {
+        Newz(42, out, count+2, SV*);
 
+        out[0] = NULL;
+
+        for (i=count; i>0; --i) {
+            out[i] = newSVsv(POPs);
+        }
+        out[count+1] = NULL;
+    }
+
+    PUTBACK;
     FREETMPS;
     LEAVE;
 
-    return sv;
+    /* pugs_setenv(old_env); */
+    return out;
 }
 
 char *
@@ -148,3 +188,65 @@
 #endif
     return(sv);
 }
+
+SV **
+perl5_apply(SV *sub, SV *inv, SV** args, int cxt)
+{
+    SV **arg;
+    SV *rv;
+    SV *sv;
+
+    dSP;
+
+    ENTER;
+    SAVETMPS;
+
+    PUSHMARK(SP);
+    if (inv != NULL) {
+        XPUSHs(inv);
+    }
+    for (arg = args; *arg != NULL; arg++) {
+        XPUSHs(*arg);
+    }
+    PUTBACK;
+
+    if (inv != NULL) {
+        perl5_return_conv(call_method(SvPV_nolen(sub), cxt|G_EVAL));
+    }
+    else {
+        perl5_return_conv(call_sv(sub, cxt|G_EVAL));
+    }
+}
+
+SV *
+perl5_newSViv ( int iv )
+{
+    return(newSViv(iv));
+}
+
+SV *
+perl5_newSVnv ( double iv )
+{
+    return(newSVnv(iv));
+}
+
+int
+perl5_SvIV ( SV *sv )
+{
+    return((int)SvIV(sv));
+}
+
+double
+perl5_SvNV ( SV *sv )
+{
+    return((double)SvNV(sv));
+}
+
+bool
+perl5_SvTRUE ( SV * sv )
+{
+    bool rv;
+    rv = SvTRUE(sv);
+    return(rv ? 1 : 0);
+}
+
diff --git a/src/Language/Perl5.hs b/src/Language/Perl5.hs
--- a/src/Language/Perl5.hs
+++ b/src/Language/Perl5.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE ForeignFunctionInterface, TypeSynonymInstances, ScopedTypeVariables #-}
+{-# LANGUAGE ForeignFunctionInterface, TypeSynonymInstances, ScopedTypeVariables, FlexibleInstances, UndecidableInstances, OverlappingInstances #-}
 {-# INCLUDE "p5embed.h" #-}
 
 module Language.Perl5
@@ -6,13 +6,21 @@
     , ToSV(..)
     , FromSV(..)
     , withPerl5
+    , callSub,      (.:), (.!)
+    , callMethod,   (.$), (.$!)
     , eval
+    , eval_
+    , SV
+    , use
     ) where
 import Foreign
 import Foreign.C.Types
 import Foreign.C.String
-import Control.Exception (bracket)
+import Control.Exception (bracket, throwIO, Exception(..))
+import Data.Dynamic (toDyn)
+import Data.List (intersperse)
 
+-- | Perl 5's calling context.
 data Context = Void | Item | List
 
 enumContext :: (Num a) => Context -> a
@@ -23,6 +31,52 @@
 type Interpreter = Ptr ()
 type SV = Ptr ()
 
+class ToCV a where
+    toCV :: a -> Int -> IO SV
+
+instance ToSV a => ToCV a where
+    toCV x _ = toSV x
+
+instance ToCV String where
+    toCV sub count = do
+        let prms = map (\i -> "$_[" ++ show i ++ "]") [0 .. count-1]
+        eval ("sub { " ++ sub ++ "(" ++ (concat $ intersperse ", " prms) ++ ") }")
+
+(.:) :: (ToCV sub, ToArgs args, FromArgs ret) => sub -> args -> IO ret
+(.:) = callSub
+
+(.!) :: (ToCV sub, ToArgs args) => sub -> args -> IO ()
+(.!) = callSub
+
+-- | Call a Perl 5 subroutine.
+callSub :: forall s a r. (ToCV s, ToArgs a, FromArgs r) => s -> a -> IO r
+callSub sub args = do
+    args'   <- toArgs args
+    sub'    <- toCV sub (length args')
+    rv      <- withArray0 nullPtr args' $ \argsPtr -> do
+        perl5_apply sub' nullPtr argsPtr (enumContext $ contextOf (undefined :: r))
+    returnPerl5 rv
+
+(.$) :: (ToSV meth, ToArgs args, FromArgs ret) => SV -> meth -> args -> IO ret
+(.$) = callMethod
+
+(.$!) :: (ToSV meth, ToArgs args) => SV -> meth -> args -> IO ()
+(.$!) = callMethod
+
+-- | Call a Perl 5 method.
+callMethod :: forall i m a r. (ToSV i, ToSV m, ToArgs a, FromArgs r) => i -> m -> a -> IO r
+callMethod inv meth args = do
+    inv'    <- toSV inv
+    args'   <- toArgs args
+    sub'    <- toSV meth
+    rv      <- withArray0 nullPtr args' $ \argsPtr -> do
+        perl5_apply sub' inv' argsPtr (enumContext $ contextOf (undefined :: r))
+    returnPerl5 rv
+
+-- | Use a module.  Returns a prototype object representing the module.
+use :: String -> IO SV
+use m = eval $ "use " ++ m ++ "; q[" ++ m ++ "]"
+
 -- | Run a computation within the context of a Perl 5 interpreter. 
 withPerl5 :: IO a -> IO a
 withPerl5 f = do
@@ -33,11 +87,23 @@
                 perl_free interp) (const f)
 
 -- | Evaluate a snippet of Perl 5 code.
-eval :: forall a. FromSV a => String -> IO a
-eval str = withCString str $ \cstr -> do
-    sv <- perl5_eval cstr (enumContext $ contextOf (undefined :: a))
-    fromSV sv
+eval :: forall a. FromArgs a => String -> IO a
+eval str = withCStringLen str $ \(cstr, len) -> do
+    rv  <- perl5_eval cstr (toEnum len) (enumContext $ contextOf (undefined :: a))
+    returnPerl5 rv 
 
+-- | Same as 'eval' but always in void context.
+eval_ :: String -> IO ()
+eval_ str = eval str
+
+returnPerl5 :: forall a. FromArgs a => Ptr SV -> IO a
+returnPerl5 rv = do
+    svs <- peekArray0 nullPtr rv
+    case svs of
+        []      -> fromArgs =<< peekArray0 nullPtr (rv `advancePtr` 1)
+        [err]   -> throwIO (DynException $ toDyn err)
+        (_:x:_) -> fail =<< fromSV x
+
 -- | Data types that can be casted into a Perl 5 value (SV).
 class ToSV a where
     toSV :: a -> IO SV
@@ -45,15 +111,21 @@
 -- | Data types that can be casted from a Perl 5 value (SV).
 class FromSV a where
     fromSV :: SV -> IO a
-    contextOf :: a -> Context
-    contextOf _ = Item
 
+instance ToSV SV where toSV = return
+instance FromSV SV where fromSV = return
+
 instance ToSV () where
     toSV _ = perl5_sv_undef
 instance FromSV () where
     fromSV x = seq x (return ())
-    contextOf _ = Void
 
+instance ToArgs [String] where
+    toArgs = mapM toSV
+
+instance FromArgs [String] where
+    fromArgs = mapM fromSV
+
 instance ToSV String where
     toSV str = withCStringLen str $ \(cstr, len) -> do
         perl5_newSVpvn cstr (toEnum len)
@@ -62,17 +134,81 @@
         cstr <- perl5_SvPV sv
         peekCString cstr
 
+instance ToSV Int where
+    toSV = perl5_newSViv . toEnum
+
+instance ToSV Double where
+    toSV = perl5_newSVnv . realToFrac
+
+instance FromSV Int where
+    fromSV = fmap fromEnum . perl5_SvIV
+
+instance FromSV Double where
+    fromSV = fmap realToFrac . perl5_SvNV
+
+instance FromSV Bool where
+    fromSV = perl5_SvTRUE
+
+instance ToSV Bool where
+    toSV True = perl5_sv_yes
+    toSV False = perl5_sv_no
+
+class ToArgs a where
+    toArgs :: a -> IO [SV]
+
+class FromArgs a where
+    fromArgs :: [SV] -> IO a
+    contextOf :: a -> Context
+    contextOf _ = Item
+
+instance FromArgs () where
+    fromArgs _ = return ()
+    contextOf _ = Void
+
+instance ToArgs () where
+    toArgs _ = return []
+
+instance ToSV a => ToArgs a where
+    toArgs = fmap (:[]) . toSV
+
+instance (ToSV a, ToSV b) => ToArgs (a, b) where
+    toArgs (x, y) = do
+        x' <- toSV x
+        y' <- toSV y
+        return [x', y']
+
+instance FromSV a => FromArgs a where
+    fromArgs [] = fail "Can't convert an empty return list!"
+    fromArgs (x:_) = fromSV x
+    contextOf _ = Item
+
 foreign import ccall "perl5_init"
     perl5_init :: CInt -> Ptr CString -> IO Interpreter
 foreign import ccall "perl5_sv_undef"
     perl5_sv_undef :: IO SV
+foreign import ccall "perl5_sv_yes"
+    perl5_sv_yes :: IO SV
+foreign import ccall "perl5_sv_no"
+    perl5_sv_no :: IO SV
 foreign import ccall "perl5_eval"
-    perl5_eval :: CString -> CInt -> IO SV
+    perl5_eval :: CString -> CInt -> CInt -> IO (Ptr SV)
 foreign import ccall "perl5_newSVpvn"
     perl5_newSVpvn :: CString -> CInt -> IO SV
 foreign import ccall "perl5_SvPV"
     perl5_SvPV :: SV -> IO CString
+foreign import ccall "perl5_SvIV"
+    perl5_SvIV :: SV -> IO CInt
+foreign import ccall "perl5_SvNV"
+    perl5_SvNV :: SV -> IO CDouble
+foreign import ccall "perl5_newSViv"
+    perl5_newSViv :: CInt -> IO SV
+foreign import ccall "perl5_newSVnv"
+    perl5_newSVnv :: CDouble -> IO SV
 foreign import ccall "perl_destruct"
     perl_destruct :: Interpreter -> IO CInt
 foreign import ccall "perl_free"
     perl_free :: Interpreter -> IO ()
+foreign import ccall "perl5_apply"
+    perl5_apply :: SV -> SV -> Ptr SV -> CInt -> IO (Ptr SV)
+foreign import ccall "perl5_SvTRUE"
+    perl5_SvTRUE :: SV -> IO Bool
diff --git a/test.hs b/test.hs
--- a/test.hs
+++ b/test.hs
@@ -1,6 +1,23 @@
+{-# LANGUAGE ExtendedDefaultRules #-}
 import Language.Perl5
 
 main :: IO ()
 main = withPerl5 $ do
-    putStrLn =<< eval "qq[1..1]"
-    eval "print qq[ok 1\n]"
+    _Test_  <- use "Test"
+
+    "plan".!("tests", 2)
+
+    x1 <- "crypt".:("salt", "plaintext")
+    x2 <- "crypt".:("salt", "plaintext") :: IO String
+
+    "ok".![x1, x2]
+
+    ver <- _Test_.$"VERSION"$(1.00)
+    "ok".!(ver :: String)
+
+dbiDemo :: IO ()
+dbiDemo = do
+    _DBI_   <- use "DBI"
+
+    dbh <- _DBI_.$"connect"$"dbi:SQLite:foo"
+    dbh.$!"do"$"CREATE TABLE foo (id, moose)"
