diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,11 @@
+# Changelog for collect-errors
+
+## v0.1.0.0
+
+* Initial port of CollectErrors and CN from mixed-types-num-0.4.2
+
+* Simplify the code by abandoning EnsureCE and related type functions and utilities
+
+* NumErrors within CN are now a set to prevent multiple occurrences of the same error
+
+* Add CollectError or CN instances for various Prelude type classes, including Num and Floating, checking for domain violations
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Michal Konecny (c) 2021
+
+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 Author name here 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/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,35 @@
+# collect-errors
+
+`CollectErrors es t` is a monad wrapper around values of type `t` which can accommodate (a list of)
+(potential) errors of type `es` that have (maybe) occurred during the computation
+of a value.  A value may be missing, leaving only the error(s).
+
+The wrapper `CN t` is a special case of `CollectErrors es t` with `es` = `NumErrors`.
+
+The `CN` wrapper also propagates instances of `Floating`,
+allowing us to write expressions with partial
+functions (ie functions that fail for some inputs) instead of
+branching after each application of such function:
+
+    *Numeric.CollectErrors> a = 1 :: CN Double
+    *Numeric.CollectErrors> (1/(a-1))+(sqrt (a-2))
+    {{ERROR: division by 0; ERROR: out of domain: sqrt for negative arg -1.0}}
+
+as opposed to:
+
+    *Prelude> a = 1 :: Double
+    *Prelude> (1/(a-1))+(sqrt (a-2))
+    NaN
+
+Dealing with the errors can be moved outside the expression:
+
+    *Numeric.CollectErrors> a = 1 :: CN Double
+    *Numeric.CollectErrors> toEither $ 1/(a-1)
+    Left {ERROR: division by 0}
+
+    *Numeric.CollectErrors> toEither $ 1/a+(sqrt a)
+    Right 2.0
+
+The `CN` wrapper has support for **potential errors** so that it can be applied to a set arithmetic such as **interval arithmetic**.
+
+The `Floating` instance cannot be used with a set arithmetic since the instance relies on true/false comparisons but a set arithmetic has only **three-valued (true/false/undecided) comparisons**. Package [mixed-types-num](https://hackage.haskell.org/package/mixed-types-num) provides alternative numerical type classes in which three-valued (ie Kleenean) comparisons are available.
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/collect-errors.cabal b/collect-errors.cabal
new file mode 100644
--- /dev/null
+++ b/collect-errors.cabal
@@ -0,0 +1,47 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.33.0.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: 7bf0425f189848e2370d0cab1f8335a5386e11e6f03271d1faafe460c97204ff
+
+name:           collect-errors
+version:        0.1.0.0
+synopsis:       Error monad with a Float instance
+description:    Please see the README on GitHub at <https://github.com/michalkonecny/collect-errors#readme>
+category:       Math
+homepage:       https://github.com/michalkonecny/collect-errors#readme
+bug-reports:    https://github.com/michalkonecny/collect-errors/issues
+author:         Michal Konecny
+maintainer:     mikkonecny@gmail.com
+copyright:      2021 Michal Konecny
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+extra-source-files:
+    README.md
+    ChangeLog.md
+
+source-repository head
+  type: git
+  location: https://github.com/michalkonecny/collect-errors
+
+library
+  exposed-modules:
+      Control.CollectErrors
+      Control.CollectErrors.PreludeInstances
+      Control.CollectErrors.Type
+      Numeric.CollectErrors
+      Numeric.CollectErrors.PreludeInstances
+      Numeric.CollectErrors.Type
+  other-modules:
+      Paths_collect_errors
+  hs-source-dirs:
+      src
+  ghc-options: -Wall
+  build-depends:
+      QuickCheck >=2.7
+    , base >=4.7 && <5
+    , containers
+  default-language: Haskell2010
diff --git a/src/Control/CollectErrors.hs b/src/Control/CollectErrors.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/CollectErrors.hs
@@ -0,0 +1,32 @@
+module Control.CollectErrors
+(
+-- * Monad for collecting errors in expressions
+  CollectErrors(..)
+, CanBeErrors
+, CanTestErrorsCertain(..)
+, CanTestErrorsPresent(..)
+-- ** Utilities
+, noValue
+, prependErrors
+, unCollectErrors
+, (~!)
+, toEither
+, withErrorOrValue
+, filterValuesWithoutError
+, lift
+, liftCE
+, liftPair
+, lift2
+, lift2CE
+, lift1T
+, liftT1
+, lift1TCE
+, liftT1CE
+, lift2pair
+, lift1Tpair
+, liftT1pair
+)
+where
+
+import Control.CollectErrors.Type
+import Control.CollectErrors.PreludeInstances ()
diff --git a/src/Control/CollectErrors/PreludeInstances.hs b/src/Control/CollectErrors/PreludeInstances.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/CollectErrors/PreludeInstances.hs
@@ -0,0 +1,64 @@
+module Control.CollectErrors.PreludeInstances where
+
+import Prelude
+
+import Text.Printf ( printf )
+
+import Control.CollectErrors.Type
+    ( CollectErrors(CollectErrors), CanBeErrors, lift, lift2 )
+
+
+instance (CanBeErrors es, Eq v) => Eq (CollectErrors es v) where
+  (==) = liftGotValues2 "(==)" (==)
+
+instance (CanBeErrors es, Ord v) => Ord (CollectErrors es v) where
+  compare = liftGotValues2 "compare" compare
+  (<) = liftGotValues2 "(<)" (<)
+  (<=) = liftGotValues2 "(<=)" (<=)
+  (>) = liftGotValues2 "(>)" (>)
+  (>=) = liftGotValues2 "(>=)" (>=)
+  max = lift2 max
+  min = lift2 min
+
+instance (CanBeErrors es, Bounded v) => Bounded (CollectErrors es v) where
+  minBound = pure minBound
+  maxBound = pure maxBound
+
+instance (CanBeErrors es, Enum v) => Enum (CollectErrors es v) where
+  toEnum = pure . toEnum
+  fromEnum = liftGotValue "fromEnum" fromEnum
+
+instance (CanBeErrors es, Num v) => Num (CollectErrors es v) where
+  fromInteger = pure . fromInteger
+  (+) = lift2 (+)
+  (-) = lift2 (-)
+  (*) = lift2 (*)
+  abs = lift abs
+  negate = lift negate
+  signum = lift signum
+
+instance (CanBeErrors es, Real v) => Real (CollectErrors es v) where
+  toRational = liftGotValue "toRational" toRational
+
+
+{- Utilities -}
+
+errorMissingValue :: (Show t, Monoid t) => String -> t -> t2
+errorMissingValue label es = 
+  error $ printf "Missing value in %s: %s" label (show es)
+
+errorMissingValues :: (Show t, Monoid t) => String -> [t] -> t2
+errorMissingValues label ess = 
+  error $ printf "Missing value(s) in %s: %s" label (show $ mconcat ess)
+
+liftGotValue :: (CanBeErrors es) => String -> (t1 -> t) -> CollectErrors es t1 -> t
+liftGotValue _ op (CollectErrors (Just v1) _) = 
+  op v1
+liftGotValue label op (CollectErrors _ es1) = 
+  errorMissingValue label es1
+
+liftGotValues2 :: (CanBeErrors es) => String -> (t1 -> t2 -> t) -> CollectErrors es t1 -> CollectErrors es t2 -> t
+liftGotValues2 _ op (CollectErrors (Just v1) _) (CollectErrors (Just v2) _) = 
+  op v1 v2
+liftGotValues2 label op (CollectErrors _ es1) (CollectErrors _ es2) = 
+  errorMissingValues label [es1, es2]
diff --git a/src/Control/CollectErrors/Type.hs b/src/Control/CollectErrors/Type.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/CollectErrors/Type.hs
@@ -0,0 +1,203 @@
+{-# LANGUAGE ConstraintKinds #-}
+module Control.CollectErrors.Type where
+
+import Prelude
+
+import Control.Applicative ( Applicative(liftA2), liftA )
+
+import qualified Data.Set as Set
+
+import Test.QuickCheck ( Arbitrary(arbitrary) )
+
+import Text.Printf ( printf )
+
+{-|
+  A wrapper around values which can accommodate a list of
+  (potential) errors that have (maybe) occurred during the computation
+  of a value.  A value may be missing, leaving only the error(s).
+
+  Such error collection allows one to write expressions with partial
+  functions (ie functions that fail for some inputs) instead of
+  branching after each application of such function.
+  Dealing with the errors can be moved outside the expression.
+  If the error data contain enough information, their list can be used
+  to trace the source of the errors.
+-}
+data CollectErrors es v =
+  CollectErrors
+    { getMaybeValue :: Maybe v
+    , getErrors :: es }
+
+class CanTestErrorsCertain es where
+  hasCertainError :: es -> Bool
+
+instance (CanTestErrorsCertain es) => CanTestErrorsCertain (CollectErrors es v) where
+  hasCertainError (CollectErrors _ es) = hasCertainError es
+
+instance (CanTestErrorsCertain es) => CanTestErrorsCertain [es] where
+  hasCertainError = or . map hasCertainError
+
+instance (CanTestErrorsCertain es) => CanTestErrorsCertain (Set.Set es) where
+  hasCertainError = or . map hasCertainError . Set.toList
+
+class CanTestErrorsPresent es where
+  hasError :: es -> Bool
+
+instance (CanTestErrorsPresent es) => CanTestErrorsPresent (CollectErrors es v) where
+  hasError (CollectErrors _ es) = hasError es
+
+instance CanTestErrorsPresent [es] where
+  hasError = not . null
+
+instance CanTestErrorsPresent (Set.Set es) where
+  hasError = not . null
+
+type CanBeErrors es = (Monoid es, Eq es, Show es, CanTestErrorsCertain es, CanTestErrorsPresent es)
+
+instance (Show v, CanBeErrors es) => (Show (CollectErrors es v)) where
+  show (CollectErrors mv es) =
+    case mv of
+      Just v | es == mempty -> show v
+      Just v -> printf "%s{%s}" (show v) (show es)
+      Nothing -> printf "{%s}" (show es)
+
+noValue :: es -> CollectErrors es v
+noValue es = CollectErrors Nothing es
+
+prependErrors :: (Monoid es) => es -> CollectErrors es v -> CollectErrors es v
+prependErrors es1 (CollectErrors mv es2) = CollectErrors mv (es1 <> es2)
+
+{-| Unsafe way to get a value out of the CollectErrors wrapper. -}
+unCollectErrors :: Show es => CollectErrors es p -> p
+unCollectErrors (CollectErrors (Just v) _) = v
+unCollectErrors (CollectErrors _ es) = error $ "CollectErrors: " ++ show es
+
+{-| Unsafe way to get a value out of the CollectErrors wrapper. -}
+(~!) :: Show es => CollectErrors es p -> p
+(~!) = unCollectErrors
+
+{-| A safe way to get a value out of the CollectErrors wrapper. -}
+toEither ::
+  (CanBeErrors es)
+  =>
+  CollectErrors es v -> Either es v
+toEither (CollectErrors mv es) =
+  case mv of
+    Just v | es == mempty -> Right v
+    _ -> Left es
+
+withErrorOrValue :: 
+  (CanBeErrors es)
+  =>
+  (es -> t) -> (v -> t) -> CollectErrors es v -> t
+withErrorOrValue onError onValue (CollectErrors mv es) =
+  case mv of
+    Just v | es == mempty -> onValue v
+    _ -> onError es
+
+filterValuesWithoutError ::
+  (CanBeErrors es)
+  =>
+  [CollectErrors es v] -> [v]
+filterValuesWithoutError [] = []
+filterValuesWithoutError (vCE : rest) =
+  withErrorOrValue (const restDone) (: restDone) vCE
+  where
+  restDone = filterValuesWithoutError rest
+
+
+
+-- functor instances:
+
+instance Functor (CollectErrors es) where
+  fmap f (CollectErrors mv es) =
+    CollectErrors (fmap f mv) es
+
+instance (Monoid es) => Applicative (CollectErrors es) where
+  pure v = CollectErrors (Just v) mempty
+  (CollectErrors (Just a) ae) <*> (CollectErrors (Just b) be) =
+    CollectErrors (Just (a b)) (ae <> be)
+  (CollectErrors _ ae) <*> (CollectErrors _ be) =
+    CollectErrors Nothing (ae <> be)
+
+lift :: (Monoid es) => (a -> b) -> (CollectErrors es a) -> (CollectErrors es b)
+lift = liftA
+
+liftCE :: (Monoid es) => (a -> (CollectErrors es c)) -> (CollectErrors es a) -> (CollectErrors es c)
+liftCE f (CollectErrors (Just a) ae) =
+  prependErrors ae $ f a
+liftCE _ (CollectErrors _ ae) =
+    CollectErrors Nothing ae
+
+liftPair :: (Monoid es) => (a -> (c,d)) -> (CollectErrors es a) -> (CollectErrors es c, CollectErrors es d)
+liftPair f (CollectErrors (Just a) ae) = 
+  (CollectErrors (Just c) ae, CollectErrors (Just d) ae)
+  where
+  (c,d) = f a
+liftPair _ (CollectErrors _ ae) = 
+  (CollectErrors Nothing ae, CollectErrors Nothing ae)
+
+lift2 :: (Monoid es) => (a -> b -> c) -> (CollectErrors es a) -> (CollectErrors es b) -> (CollectErrors es c)
+lift2 = liftA2
+
+lift2CE :: (Monoid es) => (a -> b -> (CollectErrors es c)) -> (CollectErrors es a) -> (CollectErrors es b) -> (CollectErrors es c)
+lift2CE f (CollectErrors (Just a) ae) (CollectErrors (Just b) be) =
+  prependErrors (ae <> be) $ f a b
+lift2CE _ (CollectErrors _ ae) (CollectErrors _ be) =
+    CollectErrors Nothing (ae <> be)
+
+lift1T :: (Monoid es) => (a -> b -> c) -> (CollectErrors es a) -> b -> (CollectErrors es c)
+lift1T fn (CollectErrors (Just a) ae) b = CollectErrors (Just (fn a b)) ae
+lift1T _ (CollectErrors _ ae) _ = CollectErrors Nothing ae
+
+lift1TCE :: (Monoid es) => (a -> b -> (CollectErrors es c)) -> (CollectErrors es a) -> b -> (CollectErrors es c)
+lift1TCE fn (CollectErrors (Just a) ae) b = prependErrors ae $ fn a b
+lift1TCE _ (CollectErrors _ ae) _ = CollectErrors Nothing ae
+
+liftT1 :: (Monoid es) => (a -> b -> c) -> a -> (CollectErrors es b) -> (CollectErrors es c)
+liftT1 fn a (CollectErrors (Just b) be) = CollectErrors (Just (fn a b)) be
+liftT1 _ _ (CollectErrors _ be) = CollectErrors Nothing be
+
+liftT1CE :: (Monoid es) => (a -> b -> (CollectErrors es c)) -> a -> (CollectErrors es b) -> (CollectErrors es c)
+liftT1CE fn a (CollectErrors (Just b) be) = prependErrors be $ fn a b
+liftT1CE _ _ (CollectErrors _ be) = CollectErrors Nothing be
+
+lift2pair :: (Monoid es) => (a -> b -> (c,d)) -> (CollectErrors es a) -> (CollectErrors es b) -> (CollectErrors es c, CollectErrors es d)
+lift2pair f (CollectErrors (Just a) ae) (CollectErrors (Just b) be) = 
+  (CollectErrors (Just c) abe, CollectErrors (Just d) abe)
+  where
+  (c,d) = f a b
+  abe = ae <> be
+lift2pair _ (CollectErrors _ ae) (CollectErrors _ be) = 
+  (CollectErrors Nothing abe, CollectErrors Nothing abe)
+  where
+  abe = ae <> be
+
+lift1Tpair :: (Monoid es) => (a -> b -> (c,d)) -> (CollectErrors es a) -> b -> (CollectErrors es c, CollectErrors es d)
+lift1Tpair f (CollectErrors (Just a) ae) b = 
+  (CollectErrors (Just c) ae, CollectErrors (Just d) ae)
+  where
+  (c,d) = f a b
+lift1Tpair _ (CollectErrors _ ae) _ = 
+  (CollectErrors Nothing ae, CollectErrors Nothing ae)
+
+liftT1pair :: (Monoid es) => (a -> b -> (c,d)) -> a -> (CollectErrors es b) -> (CollectErrors es c, CollectErrors es d)
+liftT1pair f a (CollectErrors (Just b) be) = 
+  (CollectErrors (Just c) be, CollectErrors (Just d) be)
+  where
+  (c,d) = f a b
+liftT1pair _ _ (CollectErrors _ be) = 
+  (CollectErrors Nothing be, CollectErrors Nothing be)
+
+instance (Monoid es) => Monad (CollectErrors es) where
+  ae >>= f =
+    case ae of
+      CollectErrors (Just a) es1 ->
+        let (CollectErrors mv es2) = f a in
+          CollectErrors mv (es1 <> es2)
+      CollectErrors _ es ->
+        CollectErrors Nothing es
+
+instance (Arbitrary t, Monoid es) => Arbitrary (CollectErrors es t) where
+  arbitrary = (\v -> CollectErrors (Just v) mempty) <$> arbitrary
+
diff --git a/src/Numeric/CollectErrors.hs b/src/Numeric/CollectErrors.hs
new file mode 100644
--- /dev/null
+++ b/src/Numeric/CollectErrors.hs
@@ -0,0 +1,34 @@
+module Numeric.CollectErrors
+(
+  -- * Type of numeric errors
+  NumError(..), ErrorCertaintyLevel(..), NumErrors, CN, cn, unCN, (~!)
+  -- * Utilities
+, noValueNumErrorCertain, noValueNumErrorPotential
+  -- ** Applicable general collect-error utilities
+, noValue
+, prependErrors
+, prependErrorCertain
+, prependErrorPotential
+, CanTestErrorsCertain(..)
+, CanTestErrorsPresent(..)
+, toEither
+, withErrorOrValue
+, filterValuesWithoutError
+, lift
+, liftCN
+, liftPair
+, lift2
+, lift2CN
+, lift1T
+, liftT1
+, lift1TCN
+, liftT1CN
+, lift2pair
+, lift1Tpair
+, liftT1pair
+)
+where
+
+import Control.CollectErrors
+import Numeric.CollectErrors.Type
+import Numeric.CollectErrors.PreludeInstances ()
diff --git a/src/Numeric/CollectErrors/PreludeInstances.hs b/src/Numeric/CollectErrors/PreludeInstances.hs
new file mode 100644
--- /dev/null
+++ b/src/Numeric/CollectErrors/PreludeInstances.hs
@@ -0,0 +1,74 @@
+{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE FlexibleInstances #-}
+module Numeric.CollectErrors.PreludeInstances where
+
+import Prelude
+
+import Control.CollectErrors ( CollectErrors(CollectErrors), lift, lift2 )
+import Control.CollectErrors.PreludeInstances ( liftGotValue )
+import Numeric.CollectErrors.Type
+
+instance (Fractional v, Eq v) => Fractional (CN v) where
+  fromRational = pure . fromRational
+  recip = liftAcheck (==0) (\_ -> DivByZero) recip
+  (/) = liftA2checkB (==0) (\_ -> DivByZero) (/)
+
+instance (Integral v, Ord v, Show v) => Integral (CN v) where
+  quotRem (CollectErrors (Just a) ae) (CollectErrors (Just b) be) 
+    | b <= 0 = (e,e)
+    | otherwise = (CollectErrors (Just q) es, CollectErrors (Just r) es)
+    where
+    (q,r) = quotRem a b
+    es = ae <> be
+    e = noValueNumErrorCertain (OutOfDomain $ "quotRem with non-positive denominator " ++ show b)
+  quotRem (CollectErrors _ ae) (CollectErrors _ be) = (e,e)
+    where
+    e = CollectErrors Nothing (ae <> be)
+  toInteger = liftGotValue "toInteger" toInteger
+
+instance (Floating v, Ord v, Show v) => Floating (CN v) where
+  pi = pure pi
+  exp = lift exp
+  log = liftAcheckPositive "log" log
+  sqrt = liftAcheckNonnegative "sqrt" sqrt
+  (**) = lift2 (**) -- TODO: domain check
+  logBase = lift2 logBase -- TODO: domain check
+  sin = lift sin
+  cos = lift cos
+  asin = liftAcheckPlusMinusOne "asin" asin
+  acos = liftAcheckPlusMinusOne "acos" acos
+  atan = lift atan
+  sinh = lift sinh
+  cosh = lift cosh
+  asinh = lift asinh
+  acosh = lift acosh
+  atanh = lift atanh
+
+liftAcheck :: 
+  (a -> Bool) -> 
+  (a -> NumError) -> 
+  (a -> v) -> CN a -> CN v
+liftAcheck check err op aCN@(CollectErrors (Just a) _)
+  | check a = noValueNumErrorCertain (err a)
+liftAcheck _ _ op aCN = lift op aCN
+
+liftAcheckPositive :: (Ord a, Num a, Show a) => String -> (a -> v) -> CN a -> CN v
+liftAcheckPositive fnName =
+  liftAcheck (<=0) (\x -> OutOfDomain $ fnName ++ " for non-positive arg " ++ show x)
+
+liftAcheckNonnegative :: (Ord a, Num a, Show a) => String -> (a -> v) -> CN a -> CN v
+liftAcheckNonnegative fnName =
+  liftAcheck (<0) (\x -> OutOfDomain $ fnName ++ " for negative arg " ++ show x)
+
+liftAcheckPlusMinusOne :: (Ord a, Num a, Show a) => String -> (a -> v) -> CN a -> CN v
+liftAcheckPlusMinusOne fnName =
+  liftAcheck (\x -> -1 <= x && x <= 1) (\x -> OutOfDomain $ fnName ++ " for illegal arg " ++ show x)
+
+liftA2checkB :: 
+  (b -> Bool) -> 
+  (b -> NumError) -> 
+  (a -> b -> v) -> 
+  CN a -> CN b -> CN v
+liftA2checkB checkB errB op a bCN@(CollectErrors (Just b) _)
+  | checkB b = noValueNumErrorCertain (errB b)
+liftA2checkB _ _ op a bCN = lift2 op a bCN
diff --git a/src/Numeric/CollectErrors/Type.hs b/src/Numeric/CollectErrors/Type.hs
new file mode 100644
--- /dev/null
+++ b/src/Numeric/CollectErrors/Type.hs
@@ -0,0 +1,75 @@
+{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+module Numeric.CollectErrors.Type 
+
+where
+
+import qualified Data.List as List
+import qualified Data.Set as Set
+
+import Control.CollectErrors
+    ( CanTestErrorsCertain(..), CollectErrors, noValue, prependErrors, liftCE, lift2CE, lift1TCE, liftT1CE, unCollectErrors, CanTestErrorsPresent )
+
+cn :: v -> CN v
+cn = pure
+
+unCN :: CN p -> p
+unCN = unCollectErrors
+
+type CN = CollectErrors NumErrors
+newtype NumErrors = NumErrors (Set.Set NumErrorLevel)
+  deriving (Eq,Semigroup, Monoid, CanTestErrorsCertain, CanTestErrorsPresent)
+type NumErrorLevel = (NumError, ErrorCertaintyLevel)
+
+instance Show NumErrors where
+  show (NumErrors set) =
+    "{" <> (List.intercalate "; " $ map showEL $ Set.toList set)  <>  "}"
+    where
+    showEL (e,l) =
+      show l <> ": " <> show e
+
+data NumError =
+    DivByZero | OutOfDomain String | NumError String
+    deriving (Eq, Ord)
+
+instance Show NumError where
+  show DivByZero = "division by 0"
+  show (OutOfDomain s) = "out of domain: " ++ s
+  show (NumError s) = "numeric error: " ++ s
+
+data ErrorCertaintyLevel =
+  ErrorCertain | ErrorPotential
+  deriving (Eq, Ord)
+
+instance Show ErrorCertaintyLevel where
+  show ErrorCertain = "ERROR"
+  show ErrorPotential = "POTENTIAL ERROR"
+
+instance CanTestErrorsCertain NumErrorLevel where
+  hasCertainError = (== ErrorCertain) . snd
+
+{-| Construct an empty wrapper indicating that given error has certainly occurred. -}
+noValueNumErrorCertain :: NumError -> CN v
+noValueNumErrorCertain e = noValue $ NumErrors $ Set.singleton (e, ErrorCertain)
+
+{-| Construct an empty wrapper indicating that given error may have occurred. -}
+noValueNumErrorPotential :: NumError -> CN v
+noValueNumErrorPotential e = noValue $ NumErrors $ Set.singleton (e, ErrorPotential)
+
+prependErrorCertain :: NumError -> CN t -> CN t
+prependErrorCertain e = prependErrors $ NumErrors $ Set.singleton (e, ErrorCertain)
+  
+prependErrorPotential :: NumError -> CN t -> CN t
+prependErrorPotential e = prependErrors $ NumErrors $ Set.singleton (e, ErrorPotential)
+
+liftCN  :: (a -> (CN c)) -> (CN a) -> (CN c)
+liftCN = liftCE
+
+lift2CN  :: (a -> b -> (CN c)) -> (CN a) -> (CN b) -> (CN c)
+lift2CN = lift2CE
+
+lift1TCN  :: (a -> b -> (CN c)) -> (CN a) -> b -> (CN c)
+lift1TCN = lift1TCE
+liftT1CN  :: (a -> b -> (CN c)) -> a -> (CN b) -> (CN c)
+liftT1CN = liftT1CE
