diff --git a/.travis.yml b/.travis.yml
new file mode 100644
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,56 @@
+# NB: don't set `language: haskell` here
+
+# The following enables several GHC versions to be tested; often it's enough to test only against the last release in a major GHC version. Feel free to omit lines listings versions you don't need/want testing for.
+env:
+# - GHCVER=6.12.3
+# - GHCVER=7.0.1
+# - GHCVER=7.0.2
+# - GHCVER=7.0.3
+# - GHCVER=7.0.4
+# - GHCVER=7.2.1
+# - GHCVER=7.2.2
+# - GHCVER=7.4.1
+# - GHCVER=7.4.2
+# - GHCVER=7.6.1
+# - GHCVER=7.6.2
+ - GHCVER=7.6.3
+# - GHCVER=7.8.1 # see note about Alex/Happy
+# - GHCVER=7.8.2 # see note about Alex/Happy
+ - GHCVER=7.8.3 # see note about Alex/Happy
+# - GHCVER=head  # see section about GHC HEAD snapshots
+
+# Note: the distinction between `before_install` and `install` is not important.
+before_install:
+ - travis_retry sudo add-apt-repository -y ppa:hvr/ghc
+ - travis_retry sudo apt-get update
+ - travis_retry sudo apt-get install cabal-install-1.18 ghc-$GHCVER # see note about happy/alex
+ - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/1.18/bin:$PATH
+ - |
+   if [ $GHCVER = "head" ] || [ ${GHCVER%.*} = "7.8" ]; then
+     travis_retry sudo apt-get install happy-1.19.3 alex-3.1.3
+     export PATH=/opt/alex/3.1.3/bin:/opt/happy/1.19.3/bin:$PATH
+   else
+     travis_retry sudo apt-get install happy alex
+   fi
+
+install:
+ - cabal update
+ - cabal install --only-dependencies --enable-tests -v2  # -v2 provides useful information for debugging
+
+# Here starts the actual work to be performed for the package under test; any command which exits with a non-zero exit code causes the build to fail.
+script:
+ - cabal configure --enable-tests -v2  # -v2 provides useful information for debugging
+ - cabal build   # this builds all libraries and executables (including tests/benchmarks)
+ - cabal test
+ - cabal check
+ - cabal sdist   # tests that a source-distribution can be generated
+
+# The following scriptlet checks that the resulting source distribution can be built & installed
+ - export SRC_TGZ=$(cabal-1.18 info . | awk '{print $2 ".tar.gz";exit}') ;
+   cd dist/;
+   if [ -f "$SRC_TGZ" ]; then
+      cabal install "$SRC_TGZ";
+   else
+      echo "expected '$SRC_TGZ' not found";
+      exit 1;
+   fi
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2014, Masahiro Sakai
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Masahiro Sakai nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/extended-reals.cabal b/extended-reals.cabal
new file mode 100644
--- /dev/null
+++ b/extended-reals.cabal
@@ -0,0 +1,37 @@
+name:                extended-reals
+version:             0.1.0.0
+synopsis:            Extension of real numbers with positive/negative infinities
+description:
+  Extension of real numbers with positive/negative infinities (±∞).
+  It is useful for describing various limiting behaviors in mathematics.
+homepage:            https://github.com/msakai/extended-reals/
+license:             BSD3
+license-file:        LICENSE
+author:              Masahiro Sakai
+maintainer:          masahiro.sakai@gmail.com
+category:            Math
+build-type:          Simple
+extra-source-files:  .travis.yml
+cabal-version:       >=1.10
+bug-reports:         https://github.com/msakai/extended-reals/issues
+
+source-repository head
+  type:     git
+  location: git://github.com/msakai/extended-reals.git
+
+library
+  exposed-modules:     Data.ExtendedReal
+  other-extensions:    DeriveDataTypeable
+  build-depends:       base >=4 && <5, deepseq >=1.3 && <1.4, hashable >=1.2 && <1.3
+  hs-source-dirs:      src
+  default-language:    Haskell2010
+
+Test-suite TestExtendedReal
+  Type:              exitcode-stdio-1.0
+  HS-Source-Dirs:    test
+  Main-is:           TestExtendedReal.hs
+  Build-depends:     base, HUnit >=1.2 && <1.3, QuickCheck >=2.6 && <2.7, test-framework >=0.8 && <0.9, test-framework-th >=0.2 && <0.3, test-framework-hunit >=0.3 && <0.4, test-framework-quickcheck2 >=0.3 && <0.4, extended-reals
+  Default-Language: Haskell2010
+  Other-Extensions:
+     TemplateHaskell
+     ScopedTypeVariables
diff --git a/src/Data/ExtendedReal.hs b/src/Data/ExtendedReal.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/ExtendedReal.hs
@@ -0,0 +1,130 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.ExtendedReal
+-- Copyright   :  (c) Masahiro Sakai 2014
+-- License     :  BSD-style
+-- 
+-- Maintainer  :  masahiro.sakai@gmail.com
+-- Stability   :  provisional
+-- Portability :  non-portable (DeriveDataTypeable)
+--
+-- Extension of real numbers with positive/negative infinities (±∞).
+-- It is useful for describing various limiting behaviors in mathematics.
+--
+-- Remarks:
+--
+-- * @∞ - ∞@ is left undefined as usual,
+--   but we define @0 × ∞ = 0 × -∞ = 0@ by following the convention of
+--   probability or measure theory.
+--
+-- References:
+--
+-- * Wikipedia contributors, "Extended real number line," Wikipedia,
+--   The Free Encyclopedia, https://en.wikipedia.org/wiki/Extended_real_number_line
+--   (accessed September 1, 2014).
+--
+-----------------------------------------------------------------------------
+module Data.ExtendedReal
+  ( Extended (..)
+  , isFinite
+  , isInfinite
+  ) where
+
+import Prelude hiding (isInfinite)
+import Control.DeepSeq
+import Data.Data
+import Data.Hashable
+import Data.Typeable
+
+-- | @Extended r@ is an extension of /r/ with positive/negative infinity (±∞).
+data Extended r
+  = NegInf    -- ^ negative infinity (-∞)
+  | Finite !r -- ^ finite value
+  | PosInf    -- ^ positive infinity (+∞)
+  deriving (Ord, Eq, Show, Read, Typeable, Data)
+
+instance Bounded (Extended r) where
+  minBound = NegInf
+  maxBound = PosInf
+
+instance Functor Extended where
+  fmap _ NegInf = NegInf
+  fmap f (Finite x) = Finite (f x)
+  fmap _ PosInf = PosInf
+
+instance NFData r => NFData (Extended r) where
+  rnf (Finite x) = rnf x
+  rnf _ = ()
+
+instance Hashable r => Hashable (Extended r) where
+  hashWithSalt s NegInf     = s `hashWithSalt` (0::Int)
+  hashWithSalt s (Finite x) = s `hashWithSalt` (1::Int) `hashWithSalt` x
+  hashWithSalt s PosInf     = s `hashWithSalt` (2::Int)
+
+-- | @isFinite x = not (isInfinite x)@.
+isFinite :: Extended r -> Bool
+isFinite (Finite _) = True
+isFinite _ = False
+
+-- | @isInfinite x@ returns @True@ iff @x@ is @PosInf@ or @NegInf@.
+isInfinite :: Extended r -> Bool
+isInfinite = not . isFinite
+
+-- | Note that @Extended r@ is /not/ a field, nor a ring.
+-- 
+-- @PosInf + NegInf@ is left undefined as usual,
+-- but we define @0 * PosInf = 0 * NegInf = 0@ by following the convention of probability or measure theory.
+instance (Num r, Ord r) => Num (Extended r) where
+  Finite a + Finite b = Finite (a+b)
+  PosInf + NegInf = error "PosInf + NegInf is undefined"
+  NegInf + PosInf = error "NegInf + PosInf is undefined"
+  PosInf + _ = PosInf
+  _ + PosInf = PosInf
+  NegInf + _ = NegInf
+  _ + NegInf = NegInf
+
+  Finite x1 * e = scale x1 e
+  e * Finite x2 = scale x2 e
+  PosInf * PosInf = PosInf
+  PosInf * NegInf = NegInf
+  NegInf * PosInf = NegInf
+  NegInf * NegInf = PosInf
+
+  negate NegInf = PosInf
+  negate (Finite x) = Finite (negate x)
+  negate PosInf = NegInf
+
+  abs NegInf = PosInf
+  abs (Finite x) = Finite (abs x)
+  abs PosInf = PosInf
+
+  signum NegInf = Finite (-1)
+  signum (Finite x) = Finite (signum x)
+  signum PosInf = Finite 1
+
+  fromInteger = Finite . fromInteger  
+
+-- | Note that @Extended r@ is /not/ a field, nor a ring.
+instance (Fractional r, Ord r) => Fractional (Extended r) where
+  recip (Finite x) = Finite (1/x)
+  recip _ = Finite 0
+
+  fromRational = Finite . fromRational
+
+-- Note that we define @0 * PosInf = 0 * NegInf = 0@ by the convention of probability or measure theory.
+scale :: (Num r, Ord r) => r -> Extended r -> Extended r
+scale a e = seq e $
+  case a `compare` 0 of
+    EQ -> Finite 0
+    GT ->
+      case e of
+        NegInf   -> NegInf
+        Finite b -> Finite (a*b)
+        PosInf   -> PosInf
+    LT ->
+      case e of
+        NegInf   -> PosInf
+        Finite b -> Finite (a*b)
+        PosInf   -> NegInf
diff --git a/test/TestExtendedReal.hs b/test/TestExtendedReal.hs
new file mode 100644
--- /dev/null
+++ b/test/TestExtendedReal.hs
@@ -0,0 +1,154 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
+
+import Prelude hiding (isInfinite)
+import Control.Exception (SomeException, evaluate, try)
+import Control.Monad
+import Data.Maybe
+import System.IO.Unsafe (unsafePerformIO)
+import Test.HUnit hiding (Test)
+import Test.QuickCheck
+import Test.Framework.TH
+import Test.Framework.Providers.HUnit
+import Test.Framework.Providers.QuickCheck2
+
+import Data.ExtendedReal
+
+-- ----------------------------------------------------------------------
+
+instance Arbitrary r => Arbitrary (Extended r) where
+  arbitrary = 
+    oneof
+    [ return NegInf
+    , return PosInf
+    , liftM Finite arbitrary
+    ]
+
+eval :: a -> Maybe a
+eval a = unsafePerformIO $ do
+  ret <- try (evaluate a)
+  case ret of
+    Left (_::SomeException) -> return Nothing
+    Right b -> return $ Just b
+
+isDefined :: a -> Bool
+isDefined = isJust . eval
+
+-- ----------------------------------------------------------------------
+
+prop_add_comm :: Property
+prop_add_comm =
+  forAll arbitrary $ \(a :: Extended Rational) ->
+  forAll arbitrary $ \b ->
+    eval (a + b) == eval (b + a)
+
+prop_add_assoc :: Property
+prop_add_assoc =
+  forAll arbitrary $ \(a :: Extended Rational) ->
+  forAll arbitrary $ \b ->
+  forAll arbitrary $ \c ->
+    eval (a + (b + c)) == eval ((a + b) + c)
+
+prop_add_unit :: Property
+prop_add_unit =
+  forAll arbitrary $ \(a :: Extended Rational) ->
+    0 + a == a
+
+prop_add_monotone :: Property
+prop_add_monotone =
+  forAll arbitrary $ \(a :: Extended Rational) ->
+  forAll arbitrary $ \b ->
+  forAll arbitrary $ \c ->
+    a <= b && isDefined (a+c) && isDefined (b+c)
+    ==> a+c <= b+c
+
+prop_mult_comm :: Property
+prop_mult_comm =
+  forAll arbitrary $ \(a :: Extended Rational) ->
+  forAll arbitrary $ \b ->
+    a * b == b * a
+
+-- PosInf + NegInf is left undefined
+case_add_PosInf_NegInf :: IO ()
+case_add_PosInf_NegInf =
+  eval (PosInf + NegInf :: Extended Rational) @?= Nothing
+
+prop_mult_assoc :: Property
+prop_mult_assoc =
+  forAll arbitrary $ \(a :: Extended Rational) ->
+  forAll arbitrary $ \b ->
+  forAll arbitrary $ \c ->
+    a * (b * c) == (a * b) * c
+
+prop_mult_unit :: Property
+prop_mult_unit =
+  forAll arbitrary $ \(a :: Extended Rational) ->
+    1 * a == a
+
+prop_mult_dist :: Property
+prop_mult_dist =
+  forAll arbitrary $ \(a :: Extended Rational) ->
+  forAll arbitrary $ \b ->
+  forAll arbitrary $ \c ->
+    isDefined (a * (b + c)) && isDefined (a * b + a * c)
+    ==> eval (a * (b + c)) == eval (a * b + a * c)
+
+prop_mult_zero :: Property
+prop_mult_zero = 
+  forAll arbitrary $ \(a :: Extended Rational) ->
+    0 * a == 0
+
+prop_mult_monotone :: Property
+prop_mult_monotone =
+  forAll arbitrary $ \(a :: Extended Rational) ->
+  forAll arbitrary $ \b ->
+  forAll arbitrary $ \c ->
+    a <= b && c > 0 && isDefined (a*c) && isDefined (b*c)
+    ==> a*c <= b*c
+
+-- We define 0 * PosInf = 0
+case_mult_zero_PosInf :: IO ()
+case_mult_zero_PosInf =
+  0 * PosInf @?= (0 :: Extended Rational)
+
+-- We define 0 * NegInf = 0
+case_mult_zero_NegInf :: IO ()
+case_mult_zero_NegInf =
+  0 * NegInf @?= (0 :: Extended Rational)
+
+prop_negate_inverse :: Property
+prop_negate_inverse = 
+  forAll arbitrary $ \(a :: Extended Rational) ->
+    negate (negate a) == a
+
+prop_signum_abs :: Property
+prop_signum_abs =
+  forAll arbitrary $ \(a :: Extended Rational) ->
+    signum a * abs a == a
+
+prop_recip_inverse :: Property
+prop_recip_inverse =
+  forAll arbitrary $ \(a :: Extended Rational) ->
+    isFinite a && a /= 0 ==> recip (recip a) == a
+
+case_recip_PosInf :: IO ()
+case_recip_PosInf = recip PosInf @?= (0 :: Extended Rational)
+
+case_recip_NegInf :: IO ()
+case_recip_NegInf = recip NegInf @?= (0 :: Extended Rational)
+
+prop_NegInf_smallest :: Property
+prop_NegInf_smallest =
+  forAll arbitrary $ \(a :: Extended Rational) ->
+    NegInf <= a
+
+prop_PosInf_largest :: Property
+prop_PosInf_largest =
+  forAll arbitrary $ \(a :: Extended Rational) ->
+    a <= PosInf
+
+-- ----------------------------------------------------------------------
+-- Test harness
+
+main :: IO ()
+main = $(defaultMainGenerator)
