1. Doug Burke
  2. swish

Commits

Doug Burke  committed 2a29037

N3Formatter: special case output of xsd:boolean/integer/decimal/double literals; better match to XSD specs for to/FromRDFLabel

  • Participants
  • Parent commits dfed73a
  • Branches default

Comments (0)

Files changed (9)

File CHANGES

View file
 
   - marked Swish.Utils.DateTime as deprecated.
 
+  - The N3 formatter now writes true, 1, 1.2, 1.2e34 rather than
+    "true"^^xsd:boolean, "1"^^xsd:integer, "1.2"^^xsd:decimal
+    and "1.2e34"^^xsd:double.
+
 0.3.0.3:
 
-  - to be written
+  - changed scripts/SwishExample.ss script so that the proof succeeds.
+
+  - minor documentation improvements, including the addition of the
+    Swish script format in Swish.RDF.SwishScript.
+
+  - minor changes to behavior of Swish in several edge cases.
 
 0.3.0.2:
 
-  - to be written
+  - bugfix: stop losing triples with a bnode subject when using the
+    N3 Formatter which also makes the scripts/SwishTest.ss script run
+    successfully.
+
+  - several commands in Swish scripts now create screen
+    output as an aid to debugging.
+
+  - added the developer flag.
 
 0.3.0.1:
 
-  - to be written
+  - updated the Swish script parser to work with the changes in
+    0.3.0.0 (reported by Rick Murphy).
+
+  - several example scripts are installed in the scripts/ directory,
+    although only VehicleCapacity.ss works with this release.
 
 0.2.1 to 0.3.0.0:
 
     argument before processing any input.
 
 
-Thoughts:
-
-  - need to remove the use of :- in N3Formatter; should probably aim to
-    create turtle-compatible output where possible, with flags to control
-    the use of existential statements (@forSome), a la cwm
-
-  - I plan to move to using Text rather than String, which will mean
-    changing from Parsec to attoparsec-text (probably).
-

File Swish/RDF/N3Formatter.hs

View file
 --  This Module implements a Notation 3 formatter (see [1], [2] and [3]),
 --  for an RDFGraph value.
 --
---
 -- REFERENCES:
 --
 -- (1) <http://www.w3.org/TeamSubmission/2008/SUBM-n3-20080114/>
   rdf_type,
   rdf_nil,
   owl_sameAs, log_implies
+  , xsd_boolean, xsd_decimal, xsd_integer, xsd_double 
   )
 
 import Swish.RDF.GraphClass
 --  (b) URI nodes:  if possible, replace URI with qname,
 --      else display as <uri>
 --  (c) formula nodes (containing graphs).
---
+--  (d) use the "special-case" formats for integer/float/double
+--      literals.      
+--      
 --  [[[TODO:]]]
 --  (d) generate multi-line literals when appropriate
 --
       queueFormula lab
       return name
 
-formatLabel _ (Lit lit mlit) = return $ quoteStr lit ++ formatAnnotation mlit
+-- We assume there that the values are valid (e.g. that lit is syntactically
+-- correct).
+--      
+formatLabel _ (Lit lit (Just dtype)) 
+  | dtype `elem` [xsd_boolean, xsd_decimal, xsd_integer, xsd_double] = return $ lit
+  | otherwise = return $ quoteStr lit ++ formatAnnotation dtype
+formatLabel _ (Lit lit Nothing) = return $ quoteStr lit
 
 formatLabel _ lab = return $ show lab
 
 -- the annotation for a literal (ie type or language)
-formatAnnotation :: Maybe ScopedName -> String
-formatAnnotation Nothing = ""
-formatAnnotation (Just a)  | isLang a  = '@' : langTag a
-                           | otherwise = '^':'^': showScopedName a
+formatAnnotation :: ScopedName -> String
+formatAnnotation a  | isLang a  = '@' : langTag a
+                    | otherwise = '^':'^': showScopedName a
 
 {-
 Swish.Utils.MiscHelpers contains a quote routine

File Swish/RDF/N3Parser.hs

View file
 setPrefix :: String -> String -> N3State -> N3State
 setPrefix pre uri st =  st { prefixUris=p' }
     where
-        p'    = mapReplaceOrAdd (Namespace pre uri) (prefixUris st)
+        p' = mapReplaceOrAdd (Namespace pre uri) (prefixUris st)
 
 -- | Set name for special syntax element
 setSName :: String -> ScopedName -> N3State -> N3State
 --  Return function to update graph in N3 parser state,
 --  using the supplied function of a graph
 --  (use returned function with Parsec updateState)
-updateGraph :: ( RDFGraph -> RDFGraph ) -> ( N3State -> N3State )
+updateGraph :: ( RDFGraph -> RDFGraph ) -> N3State -> N3State
 updateGraph f s = s { graphState = f (graphState s) }
 
 ----------------------------------------------------------------------
 -}
 operatorLabel snam = (Res . flip getPrefixScopedName snam) <$> getState
 
--- Add statement to graph in N3 parser state
+{-
+Add statement to graph in N3 parser state.
+
+To support literals that are written directly/implicitly - i.e.  as
+true/false/1/1.0/1.0e23 - rather than a string with an explicit
+datatype we need to special case handling of the object label for
+literals. Is this actually needed? The N3 Formatter now doesn't
+display the xsd: datatypes on output, but there may be issues with
+other formats (e.g RDF/XML once it is supported).
+
+-}
 
 type AddStatement = RDFLabel -> N3Parser ()
 
 addStatement :: RDFLabel -> RDFLabel -> AddStatement
+addStatement s p o@(Lit _ (Just dtype)) | dtype `elem` [xsd_boolean, xsd_integer, xsd_decimal, xsd_double] = do 
+  st <- getState
+  let stmt = arc s p o
+      oldp = prefixUris st
+      ogs = graphState st
+      newp = mapReplaceOrAdd (snScope dtype) oldp
+  setState $ st { prefixUris = newp, graphState = addArc stmt ogs }
 addStatement s p o = updateState (updateGraph (addArc (arc s p o) ))
 
 addStatementRev :: RDFLabel -> RDFLabel -> AddStatement

File Swish/RDF/RDFGraph.hs

View file
 import Data.String (IsString(..))
 import Data.Time (UTCTime, Day, parseTime, formatTime)
 import System.Locale (defaultTimeLocale)  
+import Text.Printf
 
 -----------------------------------------------------------
 -- | RDF graph node values
 instance IsString RDFLabel where
   fromString = flip Lit Nothing
 
--- | A type that can be converted to a RDF Label.
---
--- The String instance converts to an untyped literal
--- (so no language tag is assumed).
---
--- The `UTCTime` and `Day` instances assume values are in UTC.
---  
--- The numeric types have not yet been checked to ensure the
--- conversion meets the lexical constraints of both Haskell
--- and RDF.  
---
+{-|
+A type that can be converted to a RDF Label.
+
+The String instance converts to an untyped literal
+(so no language tag is assumed).
+
+The `UTCTime` and `Day` instances assume values are in UTC.
+ 
+The conversion for XSD types attempts to use the
+canonical form described in section 2.3.1 of
+<http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#lexical-space>.
+  
+-}
+
 class ToRDFLabel a where
   toRDFLabel :: a -> RDFLabel
   
--- | A type that can be converted from a RDF Label,
---   with the possibility of failure.
---  
--- The String instance converts from an untyped literal
--- (so it can not be used with a string with a language tag).
---
--- The `UTCTime` and `Day` instances assume values are in UTC.
---  
--- The numeric types have not yet been checked to ensure the
--- conversion meets the lexical constraints of both Haskell
--- and RDF.  
---
+{-|
+A type that can be converted from a RDF Label,
+with the possibility of failure.
+ 
+The String instance converts from an untyped literal
+(so it can not be used with a string with a language tag).
+
+The following conversions are supported for common XSD
+types (out-of-band values result in @Nothing@):
+
+ - @xsd:boolean@ to @Bool@
+
+ - @xsd:integer@ to @Int@ and @Integer@
+
+ - @xsd:float@ to @Float@
+
+ - @xsd:double@ to @Double@
+
+ - @xsd:dateTime@ to @UTCTime@
+
+ - @xsd:date@ to @Day@
+
+-}
+
 class FromRDFLabel a where
   fromRDFLabel :: RDFLabel -> Maybe a
 
     
 fLabel :: (String -> Maybe a) -> ScopedName -> RDFLabel -> Maybe a
 fLabel conv dtype (Lit xs (Just dt)) | dt == dtype = conv xs
-                                     | otherwise = Nothing
+                                     | otherwise   = Nothing
 fLabel _    _     _ = Nothing
   
-tLabel :: (Show a) => ScopedName -> a -> RDFLabel                      
-tLabel dtype = flip Lit (Just dtype) . show                      
+tLabel :: (Show a) => ScopedName -> (String -> String) -> a -> RDFLabel                      
+tLabel dtype conv = flip Lit (Just dtype) . conv . show                      
 
 instance ToRDFLabel Char where
   toRDFLabel = flip Lit Nothing . (:[])
   fromRDFLabel (Lit [c] Nothing) = Just c
   fromRDFLabel _ = Nothing
 
-instance ToRDFLabel [Char] where
+instance ToRDFLabel String where
   toRDFLabel = flip Lit Nothing
 
-instance FromRDFLabel [Char] where
+instance FromRDFLabel String where
   fromRDFLabel (Lit xs Nothing) = Just xs
   fromRDFLabel _ = Nothing
 
 instance ToRDFLabel Bool where
-  toRDFLabel = tLabel xsd_boolean
+  toRDFLabel b = Lit (if b then "true" else "false") (Just xsd_boolean)
+                                                 
+instance FromRDFLabel Bool where
+  fromRDFLabel = fLabel conv xsd_boolean
+    where
+      conv s | s `elem` ["1", "true"]  = Just True
+             | s `elem` ["0", "false"] = Just False
+             | otherwise               = Nothing
+
+fromRealFloat :: (RealFloat a, PrintfArg a) => ScopedName -> a -> RDFLabel
+fromRealFloat dtype f | isNaN f      = toL "NaN"
+                      | isInfinite f = toL $ if f > 0.0 then "INF" else "-INF"
+                      | otherwise    = toL $ printf "%E" f
+                        where
+                          toL = flip Lit (Just dtype)
+
+toRealFloat :: (RealFloat a, Read a) => (a -> Maybe a) -> ScopedName -> RDFLabel -> Maybe a
+toRealFloat conv = fLabel rconv
+    where
+      rconv "NaN"  = Just (0.0/0.0) -- how best to create a NaN?
+      rconv "INF"  = Just (1.0/0.0) -- ditto for Infinity
+      rconv "-INF" = Just ((-1.0)/0.0)
+      rconv istr 
+        -- xsd semantics allows "2." but Haskell syntax does not so add on a "0" in this case
+        | null istr        = Nothing
+        | last istr == '.' = maybeRead (istr ++ "0") >>= conv
+        | otherwise        = maybeRead istr >>= conv
+      
+instance ToRDFLabel Float where
+  toRDFLabel = fromRealFloat xsd_float
   
-instance FromRDFLabel Bool where
-  fromRDFLabel = fLabel maybeRead xsd_boolean
-
-instance ToRDFLabel Float where
-  toRDFLabel = tLabel xsd_float
-  
-{-
-As reads "<invalid float>" returns some form of Inf
-we need to catch this.
--}
-
 instance FromRDFLabel Float where
-  fromRDFLabel = fLabel (\istr -> maybeRead istr >>= conv) xsd_float
+  fromRDFLabel = toRealFloat conv xsd_float
     where
-      conv :: Float -> Maybe Float
-      conv i | isNaN i || isInfinite i || isDenormalized i = Nothing
-             | otherwise = Just . realToFrac $ i -- or fromRational . toRational
-
+      -- assume that an invalid value (NaN/Inf) from maybeRead means
+      -- that the value is out of bounds for Float so we do not
+      -- convert
+      conv f | isNaN f || isInfinite f = Nothing
+             | otherwise               = Just f
+                 
 instance ToRDFLabel Double where
-  toRDFLabel = tLabel xsd_double
+  toRDFLabel = fromRealFloat xsd_double
   
 instance FromRDFLabel Double where
-  fromRDFLabel = fLabel maybeRead xsd_double
-
+  fromRDFLabel = toRealFloat Just xsd_double
+  
 -- TODO: are there subtypes of xsd::integer that are  
 --       useful here?  
 --         
 -- TODO: add in support for Int8/..., Word8/...  
 --  
 instance ToRDFLabel Int where
-  toRDFLabel = tLabel xsd_integer
+  toRDFLabel = tLabel xsd_integer id
 
 {-
 it appears that reads doesn't fail when the input is outside
         in if (i >= lb) && (i <= ub) then Just (fromIntegral i) else Nothing
 
 instance ToRDFLabel Integer where
-  toRDFLabel = tLabel xsd_integer
+  toRDFLabel = tLabel xsd_integer id
 
 instance FromRDFLabel Integer where
   fromRDFLabel = fLabel maybeRead xsd_integer

File TODO

View file
 - improve test coverage (-fhpc cabal flag)
 
 - how much of the support code - e.g. Swish.Utils.LookupMap - can now
-  be replaced with packages from hackage? Swish.Utils.DateTime is an
-  obvious candidate.
-
-- add top-level modules - e.g. Swish or Swish.RDF - for documentation
-  (partly done) and a simple way to load up a useful set of modules.
+  be replaced with packages from hackage? Swish.Utils.DateTime is now
+  marked as deprecated since it isn't used by any other module.
 
 - move to camel case for names, in particular for
   Swish.RDF.Vocabulary; this would require a minor version update
 - change SwishAction from a tuple to a SwishStateIO (); requires an
   minor version update
 
-- add URI instances (ScopedName "?" I think) for To/FromRDFLabel
+  can we improve the processing of the commands, so that they
+  exit on error immediately, with a single error message.
 
-- N3Formatter should output integer/float/bool/... as "native"
-  values rather than e.g. "1"^^xsd:integer 
-
-  NTriples does not support this syntax, does it?
-
-- can Swish.Utils.DateTime be replaced by existing routines (do
-  not remove the module yet, mark as deprecate) 
+  A DSL for the command language?
 
 - check that the syntax supported by Read is compatible with
   RDF for To/FromLabel conversions of int/real types.
 
+- remove the containedIn function of the LDGraph type class,
+  or implement it. It is currently unused in the code base.
+

File swish.cabal

View file
   The modules "Swish" and "Swish.RDF" have been introduced to provide
   documentation. The module "Swish.Utils.DateTime" is deprecated and
   will be removed in a later release.
+  The N3 formatter now writes out literals with xsd:boolean, xsd:integer, xsd:decimal
+  and xsd:double types as literals rather than as a typed string.
   .
   [Version 0.3.0.3] Changed @scripts/SwishExample.ss@ script so that the
   proof succeeds. Some documentation improvements, including a discussion

File tests/N3FormatterTest.hs

View file
   "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n" ++ 
   commonPrefixes ++ 
   "\n" ++ -- TODO: why do we need this?
-  "base1:s1 base1:p1 \"-2.304e-108\"^^xsd:double,\n" ++ 
-  "                  \"12\"^^xsd:integer,\n" ++ 
-  "                  \"23.4\"^^xsd:float,                  \"True\"^^xsd:boolean .\n"
+  "base1:s1 base1:p1 -2.304E-108,\n" ++ 
+  "                  12,\n" ++ 
+  "                  \"2.34E1\"^^xsd:float,                  true .\n"
   
-{-
-
--- this is more a parser than formatter test; at the moment we
--- do not include it.
-
-simpleN3Graph_l3a :: String
-simpleN3Graph_l3a =
-  "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n" ++ 
-  commonPrefixes ++ 
-  "base1:s1 base1:p1 \"12\"^^xsd:integer , \n" ++
-  "  \"23.4\"^^xsd:float \n" ++
-  "  \"-2.304e-108\"^^xsd:double \n" ++
-  "  true .\n"
-  
--}
-
--- diag13 = diagTest "trivialTest13" x13a simpleN3Graph_x13a
-
 trivialTestSuite :: Test
 trivialTestSuite = TestList
  [ formatTest "trivialTest01" g1np simpleN3Graph_g1_01

File tests/N3ParserTest.hs

View file
 
 import Swish.RDF.RDFGraph
     ( RDFGraph, RDFLabel(..), NSGraph(..)
-    -- LookupNamespace(..), Namespace
-    , emptyNamespaceMap
-    , LookupFormula(..), emptyFormulaMap
+    , LookupFormula(..)
     , emptyRDFGraph, toRDFGraph
-      -- Export selected RDFLabel values
     , res_rdf_type, res_rdf_first, res_rdf_rest, res_rdf_nil
     , res_owl_sameAs, res_log_implies
     )
     ( namespaceRDF
     , langName
     , rdf_XMLLiteral
+    , xsd_boolean 
+    , xsd_integer
+    , xsd_decimal 
+    , xsd_double 
     )
 
 import Swish.Utils.QName (QName, qnameFromURI)
 
 import Test.HUnit (Test(TestCase,TestList), assertEqual, runTestTT)
 
+import Data.Monoid (Monoid(..))
 import Data.List (intercalate)
 
 ------------------------------------------------------------
 base4 = Namespace "base4" "http://id.ninebynine.org/wip/2003/test/graph3/nodebase"
 basea = Namespace "a" "http://example.org/basea#"
 
+xsdNS :: Namespace
+xsdNS = Namespace "xsd" "http://www.w3.org/2001/XMLSchema#"
+
 u1 :: RDFLabel
 u1 = Res $ ScopedName base1 ""
 
 l3 = Lit "l3--\r\"'\\--\x0020\&--\x00A0\&--" Nothing
 
 lfr, lxml, lfrxml :: RDFLabel
-lfr    = Lit "chat"          (Just $ langName "fr")
-lxml   = Lit "<br/>"         (Just rdf_XMLLiteral )
-lfrxml = Lit "<em>chat</em>" (Just rdf_XMLLiteral )
+lfr    = Lit "chat"          $ Just $ langName "fr"
+lxml   = Lit "<br/>"         $ Just rdf_XMLLiteral
+lfrxml = Lit "<em>chat</em>" $ Just rdf_XMLLiteral
 
 bTrue, bFalse :: RDFLabel
-bTrue  = Lit "true"  $ Just $ ScopedName (Namespace "xsd" "http://www.w3.org/2001/XMLSchema#") "boolean"
-bFalse = Lit "false" $ Just $ ScopedName (Namespace "xsd" "http://www.w3.org/2001/XMLSchema#") "boolean"
+bTrue  = Lit "true"  $ Just xsd_boolean
+bFalse = Lit "false" $ Just xsd_boolean
 
 f1, f2 :: RDFLabel
 f1 = Res $ ScopedName base1 "f1"
     xb5 = mUN ns5 "b5"
     xc5 = mUN ns5 "c5"
 
-nslist :: LookupMap Namespace
+nslist, xnslist :: LookupMap Namespace
 nslist = LookupMap $ map makeNewPrefixNamespace
     [ ("base1",base1)
     , ("base2",base2)
     , ("base3",base3)
     , ("base4",base4)
     ]
+xnslist = LookupMap $ map makeNewPrefixNamespace
+    [ ("base1",base1)
+    , ("base2",base2)
+    , ("base3",base3)
+    , ("base4",base4)
+    , ("xsd", xsdNS)
+    ]
 
 toGraph :: [Arc RDFLabel] -> RDFGraph
-toGraph stmts = NSGraph { namespaces = nslist
-                        , formulae   = emptyFormulaMap
+toGraph stmts = mempty { namespaces = nslist
                         , statements = stmts
                         }
 
 tx1212 = arc b4 p2 o2
 
 x12fg :: RDFGraph
+x12fg  = mempty { statements = [tx1211,tx1212] }
+{-
 x12fg  = NSGraph
         { namespaces = emptyNamespaceMap
         , formulae   = emptyFormulaMap
         , statements = [tx1211,tx1212]
         }
+-}
         
 x12 :: RDFGraph
 x12    = NSGraph
 litN3Graph_g2 :: String
 litN3Graph_g2 =
     commonPrefixes ++
+    "@prefix xsd: <" ++ nsURI xsdNS ++ "> . \n" ++
+    " base1:s1 base1:p1 \"true\"^^xsd:boolean.\n" ++
+    " base2:s2 base2:p2 \"false\"^^xsd:boolean.\n" ++
+    " base3:s3 base3:p3 \"true\"^^xsd:boolean.\n"
+
+litN3Graph_g3 :: String
+litN3Graph_g3 =
+    commonPrefixes ++
     " base1:s1 base1:p1 @true.\n" ++
     " base2:s2 base2:p2 @false.\n" ++
     " base3:s3 base3:p3 true.\n"
     
+litN3Graph_g4 :: String
+litN3Graph_g4 =
+    commonPrefixes ++
+    " base1:s1 base1:p1 ( true 1 2.0 -2.21 -2.3e-4 ).\n"
+
 lit_g1 :: RDFGraph
 lit_g1 = toGraph [ arc s1 p1 bTrue
                  , arc s2 p2 bFalse
                  , arc s3 p3 bTrue
                  ]
 
+-- at the moment we could use lit_g1 rather than lit_g2, since
+-- the namespace map isn't used in the comparison.
+--
+lit_g2 :: RDFGraph
+lit_g2 = lit_g1 { namespaces = xnslist }
+
+bOne, b20, b221, b23e4 :: RDFLabel
+bOne  = Lit "1" $ Just xsd_integer
+b20   = Lit "2.0" $ Just xsd_decimal
+b221  = Lit "-2.21" $ Just xsd_decimal
+b23e4 = Lit "-2.3e-4" $ Just xsd_double
+
+lit_g4 :: RDFGraph
+lit_g4 = mempty {
+  namespaces = xnslist
+  , statements = [
+    arc s1 p1 b1
+    , arc b1 res_rdf_first bTrue
+    , arc b1 res_rdf_rest  b2
+    , arc b2 res_rdf_first bOne
+    , arc b2 res_rdf_rest  b3
+    , arc b3 res_rdf_first b20
+    , arc b3 res_rdf_rest  b4
+    , arc b4 res_rdf_first b221
+    , arc b4 res_rdf_rest  b5
+    , arc b5 res_rdf_first b23e4
+    , arc b5 res_rdf_rest  res_rdf_nil
+    ]
+  }
+
 litTestSuite :: Test
 litTestSuite = TestList
   [ parseTest "litTest01" litN3Graph_g1 lit_g1  noError
-  , parseTest "litTest02" litN3Graph_g2 lit_g1  noError
+  , parseTest "litTest02" litN3Graph_g2 lit_g2  noError
+  , parseTest "litTest03" litN3Graph_g3 lit_g2  noError
+  , parseTest "litTest04" litN3Graph_g4 lit_g4  noError
   ]
 
 ------------------------------------------------------------

File tests/RDFGraphTest.hs

View file
 l11  = Lit "l10" (Just rdf_XMLLiteral)   -- are these meant to both be l10?
 l12  = Lit "l10" (Just rdf_XMLLiteral)   -- if you change them some tests fail
 
+nanF, infF, ninfF :: RDFLabel
+nanF  = Lit "NaN" (Just xsd_float)
+infF  = Lit "INF" (Just xsd_float)
+ninfF = Lit "-INF" (Just xsd_float)
+
+nanD, infD, ninfD :: RDFLabel
+nanD  = Lit "NaN" (Just xsd_double)
+infD  = Lit "INF" (Just xsd_double)
+ninfD = Lit "-INF" (Just xsd_double)
+
 v1, v2, v3, v4, vb3, vb4 :: RDFLabel
 v1  = Var "v1"  
 v2  = Var "v2"  
 -- test ToRDFLabel/FromRDFlabel/IsString instances
 --
     
-testConv :: (ToRDFLabel a, FromRDFLabel a, Eq a, Show a) 
-            => String -> String -> Maybe ScopedName -> a -> Test    
+testToConv :: 
+  (ToRDFLabel a, Eq a, Show a) 
+  => String -> String -> Maybe ScopedName -> a -> Test
+testToConv lbl sVal dtype hVal = 
+  let rdfVal = Lit sVal dtype
+  in testEq (":tconv:" ++ lbl) rdfVal (toRDFLabel hVal)
+  
+testFrConv :: 
+  (FromRDFLabel a, Eq a, Show a) 
+  => String -> String -> Maybe ScopedName -> a -> Test
+testFrConv lbl sVal dtype hVal = 
+  let rdfVal = Lit sVal dtype
+  in testEq (":fconv:" ++ lbl) (Just hVal)  (fromRDFLabel rdfVal)
+  
+testConv :: 
+  (ToRDFLabel a, FromRDFLabel a, Eq a, Show a) 
+  => String -> String -> Maybe ScopedName -> a -> Test    
 testConv lbl sVal dtype hVal = 
-  let rdfVal = Lit sVal dtype
-  in TestList
-  [
-    testEq ("tconv:" ++ lbl) rdfVal       (toRDFLabel hVal)
-  , testEq ("fconv:" ++ lbl) (Just hVal)  (fromRDFLabel rdfVal)
-  ]
-    
+  TestList [ 
+    testToConv lbl sVal dtype hVal,
+    testFrConv lbl sVal dtype hVal         
+    ]
+  
 -- some conversions (e.g. toRDFTriple) are covered by  
 -- other tests
 --
     testEq "fconv:fail chr1"    (Nothing :: Maybe Char) (fromRDFLabel l1)
   , testEq "fconv:fail chr2"    (Nothing :: Maybe Char) (fromRDFLabel s1)
   , testEq "fconv:fail str1"    (Nothing :: Maybe String) (fromRDFLabel (Lit "1.23" (Just xsd_float)))
+  , testEq "fconv:fail bool1"   (Nothing :: Maybe Bool)  (fromRDFLabel l1)
+  , testEq "fconv:fail bool2"   (Nothing :: Maybe Bool)  (fromRDFLabel (Lit "True" (Just xsd_boolean))) -- should we just let this be valid?
+  , testEq "fconv:fail bool3"   (Nothing :: Maybe Bool)  (fromRDFLabel (Lit "true" (Just xsd_float)))
   , testEq "fconv:fail int1"    (Nothing :: Maybe Int)  (fromRDFLabel l1)
   , testEq "fconv:fail int2"    (Nothing :: Maybe Int)  (fromRDFLabel (Lit "123456789012345" (Just xsd_integer))) 
   , testEq "fconv:fail float1"  (Nothing :: Maybe Float)  (fromRDFLabel l1)
   , testEq "fconv:fail triple"  (Nothing :: Maybe (ScopedName, ScopedName, Int)) (fromRDFTriple t01)
                                     
     -- basic string tests
-  , testEq "tconv:emptystring1"  (Lit "" Nothing)    ""       -- want to try out IsString so do not use testConv
-  , testConv "emptystring2"       "" Nothing    (""::String)
-  , testConv "char"                "x" Nothing   'x'
-  , testEq "tconv:l1-1"          (Lit "l1" Nothing)  l1
-  , testConv "l1-2"          "l1" Nothing  ("l1"::String)
+  , testEq     "tconv:emptystring1"  (Lit "" Nothing)    ""       -- want to try out IsString so do not use testToConv
+  , testConv   "emptystring2"        ""                  Nothing    (""::String)
+  , testConv   "char"                "x"                 Nothing    'x'
+  , testToConv "l1-1"                "l1"                Nothing    l1
+  , testConv   "l1-2"                "l1"                Nothing    ("l1"::String)
     
     -- boolean
-  , testConv "True"     "True"    (Just xsd_boolean) True
-  , testConv "False"    "False"   (Just xsd_boolean) False
+  , testFrConv  "True1"    "1"       (Just xsd_boolean)   True
+  , testFrConv  "False0"   "0"       (Just xsd_boolean)   False
+  , testConv    "True"     "true"    (Just xsd_boolean)   True
+  , testConv    "False"    "false"   (Just xsd_boolean)   False
+    
+    {-
+For example, -1E4, 1267.43233E12, 12.78e-2, 12 , -0, 0 and INF are all legal literals for float.
+For example, -1E4, 1267.43233E12, 12.78e-2, 12 , -0, 0 and INF are all legal literals for double.
+
+Valid values for xsd:integer include -123456789012345678901234567890, 2147483647, 0, or -0000000000000000000005.
+
+
+     -}
     
     -- numeric types
-  , testConv "int 0"    "0"       (Just xsd_integer) (0::Int)
-  , testConv "int -10"  "-10"     (Just xsd_integer) ((-10)::Int)
-  , testConv "int 10"   "10"      (Just xsd_integer) (10::Int)
-  , testConv "integer 0"    "0"       (Just xsd_integer) (0::Integer)
-  , testConv "integer -10"  "-10"     (Just xsd_integer) ((-10)::Integer)
-  , testConv "integer 10"   "10"      (Just xsd_integer) (10::Integer)
-  , testConv "integer big"  "123456789012345678901234567890"      (Just xsd_integer) (123456789012345678901234567890::Integer)
-  , testConv "integer -big" "-123456789012345678901234567890"     (Just xsd_integer) ((-123456789012345678901234567890)::Integer)
-  , testConv "float 0"        "0.0"     (Just xsd_float) (0::Float)
-  , testConv "float 0.2"      "0.2"     (Just xsd_float) (0.2::Float)
-  , testConv "float -0.2"     "-0.2"    (Just xsd_float) ((-0.2)::Float)
-  , testConv "float 2.01e-4"  "2.01e-4"  (Just xsd_float) (0.000201::Float)
-  , testConv "float -2.01e-4" "-2.01e-4" (Just xsd_float) ((-0.000201)::Float)
-  , testConv "float 2.01e38"  "2.01e38"  (Just xsd_float) (2.01e38::Float)
-  , testConv "float -2.01e38" "-2.01e38" (Just xsd_float) ((-2.01e38)::Float)
-  , testConv "double 0"        "0.0"     (Just xsd_double) (0::Double)
-  , testConv "double 0.2"      "0.2"     (Just xsd_double) (0.2::Double)
-  , testConv "double -0.2"     "-0.2"    (Just xsd_double) ((-0.2)::Double)
-  , testConv "double 2.01e-4"  "2.01e-4"  (Just xsd_double) (0.000201::Double)
-  , testConv "double -2.01e-4" "-2.01e-4" (Just xsd_double) ((-0.000201)::Double)
-  , testConv "double 2.01e38"  "2.01e38"  (Just xsd_double) (2.01e38::Double)
-  , testConv "double -2.01e38" "-2.01e38" (Just xsd_double) ((-2.01e38)::Double)
-  , testConv "double 2.01e108"  "2.01e108"  (Just xsd_double) (2.01e108::Double)
-  , testConv "double -2.01e108" "-2.01e108" (Just xsd_double) ((-2.01e108)::Double)
+  , testConv   "int 0"    "0"       (Just xsd_integer) (0::Int)
+  , testConv   "int -10"  "-10"     (Just xsd_integer) ((-10)::Int)
+  , testConv   "int 10"   "10"      (Just xsd_integer) (10::Int)
+  , testConv   "integer 0"    "0"       (Just xsd_integer) (0::Integer)
+  , testConv   "integer -10"  "-10"     (Just xsd_integer) ((-10)::Integer)
+  , testConv   "integer 10"   "10"      (Just xsd_integer) (10::Integer)
+  , testFrConv "integer -0..05" "-0000000000000000000005" (Just xsd_integer)  ((-5)::Integer)
+  , testConv   "integer big"  "123456789012345678901234567890"      (Just xsd_integer) (123456789012345678901234567890::Integer)
+  , testConv   "integer -big" "-123456789012345678901234567890"     (Just xsd_integer) ((-123456789012345678901234567890)::Integer)
+  
+  , testToConv "float NaN"    "NaN"          (Just xsd_float)   ((0.0::Float)/0.0)
+  , testToConv "float INF"    "INF"          (Just xsd_float)   ((1.0::Float)/0.0)
+  , testToConv "float -INF"   "-INF"         (Just xsd_float)   (((-1.0)::Float)/0.0)
+  , testEq     ":fconv:float NaN"  (Just True)  (fmap isNaN (fromRDFLabel nanF :: Maybe Float))
+  , testEq     ":fconv:float INF"  (Just True)  (fmap isInfinite (fromRDFLabel infF :: Maybe Float))
+  , testEq     ":fconv:float -INF" (Just True)  (fmap isInfinite (fromRDFLabel ninfF :: Maybe Float))
+  
+  , testToConv "double NaN"    "NaN"          (Just xsd_double)   ((0.0::Double)/0.0)
+  , testToConv "double INF"    "INF"          (Just xsd_double)   ((1.0::Double)/0.0)
+  , testToConv "double -INF"   "-INF"         (Just xsd_double)   (((-1.0)::Double)/0.0)
+  , testEq     ":fconv:double NaN"  (Just True)  (fmap isNaN (fromRDFLabel nanD :: Maybe Double))
+  , testEq     ":fconv:double INF"  (Just True)  (fmap isInfinite (fromRDFLabel infD :: Maybe Double))
+  , testEq     ":fconv:double -INF" (Just True)  (fmap isInfinite (fromRDFLabel ninfD :: Maybe Double))
+  
+  , testFrConv "float 0.0"      "0.0"       (Just xsd_float)   (0::Float)
+  , testToConv "float 0.0"      "0.0E0"     (Just xsd_float)   (0::Float)
+  , testFrConv "float 0."       "0."        (Just xsd_float)   (0::Float)
+  , testFrConv "float -0"       "-0"        (Just xsd_float)   (0::Float)
+  , testFrConv "float 0.2"      "0.2"       (Just xsd_float) (0.2::Float)
+  , testToConv "float 0.2"      "2.0E-1"    (Just xsd_float) (0.2::Float)
+  , testFrConv "float -0.2"     "-0.2"      (Just xsd_float) ((-0.2)::Float)
+  , testToConv "float -0.2"     "-2.0E-1"   (Just xsd_float) ((-0.2)::Float)
+  , testConv   "float 2.01e-4"  "2.01E-4"   (Just xsd_float) (0.000201::Float)
+  , testConv   "float -2.01e-4" "-2.01E-4"  (Just xsd_float) ((-0.000201)::Float)
+  , testConv   "float 2.01e38"  "2.01E38"   (Just xsd_float) (2.01e38::Float)
+  , testConv   "float -2.01e38" "-2.01E38"  (Just xsd_float) ((-2.01e38)::Float)
+    
+  , testFrConv "double 0"        "0.0"     (Just xsd_double) (0::Double)
+  , testToConv "double 0"        "0.0E0"   (Just xsd_double) (0::Double)
+  , testFrConv "double 0."       "0."      (Just xsd_double)   (0::Double)
+  , testFrConv "double -0"       "-0"      (Just xsd_double)   (0::Double)
+  , testFrConv "double 0.2"      "0.2"     (Just xsd_double) (0.2::Double)
+  , testToConv "double 0.2"      "2.0E-1"  (Just xsd_double) (0.2::Double)
+  , testFrConv "double -0.2"     "-0.2"    (Just xsd_double) ((-0.2)::Double)
+  , testToConv "double -0.2"     "-2.0E-1" (Just xsd_double) ((-0.2)::Double)
+  , testFrConv "double 2.01e-4"  "2.01e-4"  (Just xsd_double) (0.000201::Double)
+  , testToConv "double 2.01e-4"  "2.01E-4"  (Just xsd_double) (0.000201::Double)
+  , testFrConv "double -2.01e-4" "-2.01e-4" (Just xsd_double) ((-0.000201)::Double)
+  , testToConv "double -2.01e-4" "-2.01E-4" (Just xsd_double) ((-0.000201)::Double)
+  , testConv   "double 2.01e38"  "2.01E38"  (Just xsd_double) (2.01e38::Double)
+  , testConv   "double -2.01e38" "-2.01E38" (Just xsd_double) ((-2.01e38)::Double)
+  , testConv   "double 2.01e108"  "2.01E108"  (Just xsd_double) (2.01e108::Double)
+  , testConv   "double -2.01e108" "-2.01E108" (Just xsd_double) ((-2.01e108)::Double)
   
     -- URI related types
   , testEq "tconv:sname s1"    s1             (toRDFLabel qb1s1)
   , testEq "fconv:sname s1"    (Just qb1s1)   (fromRDFLabel s1)
     
     -- time values
-  , testConv "time1"   "1970-01-01T00:00:00Z"            (Just xsd_dateTime)  utc1
-  , testEq   "tconv:time2"   (Lit "2011-02-28T20:04:02.304Z" (Just xsd_dateTime))  (toRDFLabel utc2)
-  , testEq   "fconv:time2a"  (Just utc2)                                           (fromRDFLabel (Lit "2011-02-28T20:04:02.304Z" (Just xsd_dateTime)))
-  , testEq   "fconv:time2b"  (Just utc2)                                           (fromRDFLabel (Lit "2011-02-28T17:04:02.304-03:00" (Just xsd_dateTime)))
-  , testEq   "fconv:time2c"  (Just utc2)                                           (fromRDFLabel (Lit "2011-03-01T00:04:02.304+04:00" (Just xsd_dateTime)))
-  , testEq   "fconv:time2d"  (Just utc2)                                           (fromRDFLabel (Lit "2011-02-28T20:04:02.304" (Just xsd_dateTime)))
-  , testConv "time2Z"  "2011-02-28T20:04:02.304Z"        (Just xsd_dateTime)  utc2
+  , testConv   "time1"   "1970-01-01T00:00:00Z"            (Just xsd_dateTime)  utc1
+  , testToConv "time2"   "2011-02-28T20:04:02.304Z"        (Just xsd_dateTime)  utc2
+  , testFrConv "time2a"  "2011-02-28T20:04:02.304Z"        (Just xsd_dateTime)  utc2
+  , testFrConv "time2b"  "2011-02-28T17:04:02.304-03:00"   (Just xsd_dateTime)  utc2
+  , testFrConv "time2c"  "2011-03-01T00:04:02.304+04:00"   (Just xsd_dateTime)  utc2
+  , testFrConv "time2d"  "2011-02-28T20:04:02.304"         (Just xsd_dateTime)  utc2
+  , testConv   "time2Z"  "2011-02-28T20:04:02.304Z"        (Just xsd_dateTime)  utc2
                               
-  , testConv "day1a"   "1970-01-01Z"      (Just xsd_date) day1
-  , testEq   "fconv:day1b"  (Just day1)   (fromRDFLabel (Lit "1970-01-01" (Just xsd_date)))
-  , testEq   "fconv:day1c"  (Just day1)   (fromRDFLabel (Lit "1970-01-01-03:00" (Just xsd_date)))
-  , testEq   "fconv:day1d"  (Just day1)   (fromRDFLabel (Lit "1970-01-01+04:00" (Just xsd_date)))
+  , testConv   "day1a"   "1970-01-01Z"                     (Just xsd_date)      day1
+  , testFrConv "day1b"   "1970-01-01"                      (Just xsd_date)      day1
+  , testFrConv "day1c"   "1970-01-01-03:00"                (Just xsd_date)      day1
+  , testFrConv "day1d"   "1970-01-01+04:00"                (Just xsd_date)      day1
     
     -- basic fromRDFTriple test