packages feed

liboleg 0.1.1 → 0.2

raw patch · 5 files changed

+379/−2 lines, 5 filesdep +template-haskellPVP ok

version bump matches the API change (PVP)

Dependencies added: template-haskell

API changes (from Hackage documentation)

+ Text.GenPrintF: FD_lit :: String -> FDesc
+ Text.GenPrintF: FD_str :: FDesc
+ Text.GenPrintF: RString :: String -> RString
+ Text.GenPrintF: class SPrintF r
+ Text.GenPrintF: convert_to_fdesc :: String -> [FDesc]
+ Text.GenPrintF: data FDesc
+ Text.GenPrintF: instance (Show a, SPrintF r) => SPrintF (a -> r)
+ Text.GenPrintF: instance Eq FDesc
+ Text.GenPrintF: instance SPrintF RString
+ Text.GenPrintF: instance Show FDesc
+ Text.GenPrintF: newtype RString
+ Text.GenPrintF: pr_aux :: (SPrintF r) => [FDesc] -> [String] -> r
+ Text.GenPrintF: unR :: RString -> String
+ Text.TFTest: FPrIO :: ((IO () -> a) -> b) -> FPrIO a b
+ Text.TFTest: instance FormattingSpec FPrIO
+ Text.TFTest: newtype FPrIO a b
+ Text.TotalPrintF: (^) :: (FormattingSpec repr) => repr b c -> repr a b -> repr a c
+ Text.TotalPrintF: instance Eq FDesc
+ Text.TotalPrintF: instance Show FDesc
+ Text.TotalPrintF: spec :: String -> ExpQ
+ Text.TotalPrintF: sprintf :: FPr String b -> b
+ Text.TotalPrintF: sscanf :: String -> FSc a b -> b -> Maybe a

Files

Language/TEval/TInfT.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE PatternGuards #-} -- | Simply-typed Curry-style (nominal) lambda-calculus -- with integers and zero-comparison -- Type inference
+ Text/GenPrintF.hs view
@@ -0,0 +1,120 @@++-- | +--+-- <http://okmij.org/ftp/typed-formatting/FPrintScan.html#print-show>+--+--+-- Generic polyvariadic printf in Haskell98+-- +-- This generalization of Text.Printf.printf is inspired by the message of Evan Klitzke, who wrote+-- on Haskell-Cafe about frequent occurrences in his code of the lines like+-- +-- >        infoM $ printf "%s saw %s with %s" (show x) (show y) (show z)+-- +-- Writing show on and on quickly becomes tiresome. It turns out, we can avoid these repeating show,+-- still conforming to Haskell98.+-- +-- Our polyvariadic generic printf is like polyvariadic show with the printf-like format string. Our+-- printf handles values of any present and future type for which there is a Show instance. For+-- example:+-- +-- >        t1 = unR $ printf "Hi there"+-- >        -- "Hi there"+-- +-- >        t2 = unR $ printf "Hi %s!" "there"+-- >        -- "Hi there!"+-- +-- >        t3 = unR $ printf "The value of %s is %s" "x" 3+-- >        -- "The value of x is 3"+-- +-- >        t4 = unR $ printf "The value of %s is %s" "x" [5]+-- >        -- "The value of x is [5]"+-- +-- The unsightly unR appears solely for Haskell98 compatibility: flexible instances remove the need+-- for it. On the other hand, Evan Klitzke's code post-processes the result of formatting with+-- infoM, which can subsume unR.+-- +-- A bigger problem with our generic printf, shared with the original Text.Printf.printf, is+-- partiality: The errors like passing too many or too few arguments to printf are caught only at+-- run-time. We can certainly do better.+-- +-- Version:  The current version is 1.1, June 5, 2009.+--+-- References+--+--  *  The complete source code with the tests. It was published in the message posted on the+--     Haskell-Cafe mailing list on Fri, 5 Jun 2009 00:57:00 -0700 (PDT)+--     <http://okmij.org/ftp/typed-formatting/GenPrintF.hs>+-- ++module Text.GenPrintF where++-- | Needed only for the sake of Haskell98+-- If we are OK with flexible instances, this newtype can be disposed of+newtype RString = RString{unR:: String} ++class SPrintF r where+    pr_aux :: [FDesc] -> [String] -> r++-- | These two instances are all we ever need++instance SPrintF RString where+    pr_aux desc acc = RString . concat . reverse $ foldl f acc desc+     where+     f acc (FD_lit s) = s : acc+     f acc FD_str     = error "Unfulfilled %s formatter"++instance (Show a, SPrintF r) => SPrintF (a->r) where+    pr_aux desc acc x = pr_aux desc' acc'+     where+     (desc',acc') = fmtx desc acc+     fmtx [] acc     = error "No formatting directive for the argument"+     fmtx (FD_lit s:desc) acc = fmtx desc (s:acc)+     fmtx (FD_str : desc) acc = (desc, unq (show x) : acc)+     unq ('"' : str) | last str == '"' = init str+     unq str  = str+++printf str = pr_aux (convert_to_fdesc str) []++-- tests++t1 = unR $ printf "Hi there"+-- "Hi there"++t2 = unR $ printf "Hi %s!" "there"+-- "Hi there!"++t3 = unR $ printf "The value of %s is %s" "x" 3+-- "The value of x is 3"++t4 = unR $ printf "The value of %s is %s" "x" [5]+-- "The value of x is [5]"++++-- | A very simple language of format descriptors+data FDesc = FD_lit String | FD_str deriving (Eq, Show)++-- Convert "insert %s here" into +-- [FD_lit "insert ", FD_str, FD_lit " here"]+convert_to_fdesc :: String -> [FDesc]+convert_to_fdesc str = +    case break (=='%') str of+      (s1,"") -> make_lit s1+      (s1,'%':'s':rest) -> make_lit s1 ++ FD_str : convert_to_fdesc rest+      (_,s2) -> error $ "bad descriptor: " ++ take 5 s2+ where+ make_lit "" = []+ make_lit str = [FD_lit str]++test_cvf = and [+    convert_to_fdesc "Simple lit" ==+       [FD_lit "Simple lit"],+    convert_to_fdesc "%s insert" ==+       [FD_str,FD_lit " insert"],+    convert_to_fdesc "insert %s here" ==+    [FD_lit "insert ",FD_str,FD_lit " here"]+    ]++
+ Text/TFTest.hs view
@@ -0,0 +1,119 @@+{-# LANGUAGE TemplateHaskell, NoMonomorphismRestriction #-}+-- The rest is Haskell98++-- | Type-safe printf and scanf with C-like formatting string+-- We also permit a generic format specifier %a to format or parse+-- any showable and readable value.+-- Our format descriptors are first-class and can be built incrementally.+-- We can use the same format descriptor to format to a string,+-- to the standard output or any other data sink. Furthermore,+-- we can use the same format descriptor to parse from a string+-- or any data source.+-- What we print we can parse, using the same descriptor.++module Text.TFTest where++import Text.TotalPrintF+import Prelude hiding ((^))++-- The following import is needed only for the extensibility test+-- at the end of the file+import Text.PrintScanF (FormattingSpec(..), PrinterParser(..)) ++t1 = sprintf $(spec "Hello, there!")+-- "Hello, there!"++t1s = sscanf "Hello, there!" $(spec "Hello, there!") ()+-- Just ()++t2 = sprintf $(spec "Hello, %s!") "there"+-- "Hello, there!"++t3 = sprintf $(spec "The value of %s is %d") "x" 3+-- "The value of x is 3"++-- What we print we can parse, using the same descriptor+t31 = let printed = sprintf desc "x" 3+          parsed  = sscanf printed desc (\s i -> (s,i))+      in (printed, parsed)+  where desc = $(spec "The value of %s is %d")+-- ("The value of x is 3",Just ("x",3))++-- Mismatch between the formatting string and the printf arguments+-- is a type error.++-- t32 = sprintf $(spec "The value of %s is %d") "x" True+--     Couldn't match expected type `Bool' against inferred type `Int'++{-+t33 = sprintf $(spec "The value of %s is %d") "x" 3 10+    Couldn't match expected type `t1 -> t'+           against inferred type `String'+    Probable cause: `printf' is applied to too many arguments+-}++t4 = let x = [9,16,25] +	 i = 2 +     in sprintf $(spec "The element number %d of %a is %a") i x (x !! i)+-- "The element number 2 of [9,16,25] is 25"++t4s = sscanf "The element number 2 of [9,16,25] is 25"+        $(spec "The element number %d of %a is %a")+        (\i a e -> (i,a::[Int],e::Int))+-- Just (2,[9,16,25],25)++++-- Demonstrating that printf is first-class+t5 = map (uncurry printer) [("x",3), ("y",5), ("z",7)]+ where+ printer = sprintf $(spec "The value of %s is %d")++-- ["The value of x is 3","The value of y is 5","The value of z is 7"]++{- An inconsistent format descriptor generates a type error++t6 = map (uncurry printer) [("x",3), ("y",5), ("z",7)]+ where+ printer = sprintf $(spec "The value of %d is %d")+    Couldn't match expected type `Int' against inferred type `[Char]'+    In the expression: "x"+    In the expression: ("x", 3)+    In the second argument of `map', namely+        `[("x", 3), ("y", 5), ("z", 7)]'++-}++-- Demonstrating that format descriptors are first-class and can be built +-- incrementally++spec71 = $(spec "The value of %s")+spec72 = $(spec " is %d")+t7 = sprintf (spec71 ^ spec72) "x" 3+-- "The value of x is 3"+++-- Extensibility test++-- Furthermore, the user can always extend printf, for example, to+-- send the formatted data to the standard output, without first building+-- the formatted output as a string.+++newtype FPrIO a b = FPrIO ((IO () -> a) -> b)++instance FormattingSpec FPrIO where+    lit str = FPrIO $ \k -> k $ putStr str+    int     = FPrIO $ \k -> \x -> k $ putStr (show x)+    char    = FPrIO $ \k -> \x -> k $ putStr [x]+    fpp (PrinterParser pr _) = FPrIO $ \k -> \x -> k $ putStr (pr x)+    (FPrIO a) ^ (FPrIO b)  = FPrIO $ \k -> a (\sa -> b (\sb -> k (sa >> sb)))++printf (FPrIO fmt) = fmt (\m -> m >> putStrLn "\n-end-of-output-")++t3io = printf $(spec "The value of %s is %d") "x" 3+{- printed on the standard output:++The value of x is 3+-end-of-output-+-}
+ Text/TotalPrintF.hs view
@@ -0,0 +1,133 @@+{-# LANGUAGE TemplateHaskell #-}+-- The rest is Haskell98++-- |+--+-- <http://okmij.org/ftp/typed-formatting/FPrintScan.html#C-like>+--+-- Safe and generic printf/scanf with C-like format string+-- +-- We implement printf that takes a C-like format string and the variable number+-- of other arguments.  Unlike C of Haskell's printf, ours is total: if the types+-- or the number of the other arguments, the values to format, does not match the+-- format string, a type error is reported at compile time.  To the familiar+-- format descriptors %s and %d we add %a to format any showable value. The latter+-- is like the format descriptor ~a of Common Lisp. Likewise, we build scanf that+-- takes a C-like format string and the consumer function with the variable number+-- of arguments. The types and the number of the arguments must match the format+-- string; a type error is reported otherwise.+-- +-- Our approach is a variation of the safe printf and scanf described+-- elsewhere on this page. We use Template Haskell to translate the format string+-- to a phrase in the DSL of format descriptors. We use the final approach to+-- embed that DSL into Haskell.+-- +-- Unlike the safe printf explained in the Template Haskell documentation, in+-- our implementation, format descriptors are first class. They can be built+-- incrementally. The same descriptor can be used both for printing and for+-- parsing. Our printf and scanf are user-extensible: library users can write+-- functions to direct format output to any suitable data sink, or to read parsed+-- data from any suitable data source such as string or a file. Finally, what is+-- formatted can be parsed back using the same format descriptor.+-- +-- Here are some of the tests from the test collection referenced below. The+-- evaluation result is given in the comments below each binding. Example t31+-- shows that format descriptors are indeed first-class. The definition t32, when+-- uncommented, raises the shown type error because the format descriptor does not+-- match the type of the corresponding argument.+--++-- Type-safe printf and scanf with C-like formatting string+-- We also permit a generic format specifier %a to format or parse+-- any showable and readable value.+--+-- Our format descriptors are first-class and can be built incrementally.+-- We can use the same format descriptor to format to a string,+-- to the standard output or to any other data sink. Furthermore,+-- we can use the same format descriptor to parse from a string+-- or any data source.+-- What we print we can parse, using the same descriptor.+--+-- We rely on Template Haskell to convert the format string into+-- the phrase of the DSL for format descriptors.+-- We use the Final approach to embed that DSL into Haskell, see+-- PrintScanF.hs+--+-- Unlike the safe printf described in the Template Haskell+-- documentation, our format descriptors are first class.+-- They can be built incrementally. They can be used both+-- for printing and for parsing. Our printf and scanf are user-extensible:+-- library users can write functions to direct format output to any+-- suitable data sink, or to read parsed data from any suitable+-- data source.+-- Please see the examples in the file TFTest.hs.++module Text.TotalPrintF (spec, sprintf, sscanf, (^)) where++import Language.Haskell.TH+import Language.Haskell.TH.Syntax+import Language.Haskell.TH.Ppr+import Prelude hiding ((^))++import Text.PrintScanF			-- EDSL of format descriptors++-- | Primitive format descriptors used here+str :: (FormattingSpec repr) => repr w (String -> w)+str  = fpp (PrinterParser id parse)+ where+ parse s = Just $ break (== ' ') s	-- the behavior of %s in C++anys :: (FormattingSpec repr, Show a, Read a) => repr w (a -> w)+anys = fpp showread++-- | Converting from formatting strings to format descriptors+fdesc_to_code :: [FDesc] -> ExpQ+fdesc_to_code [d] = cnv1 d+fdesc_to_code (d:desc) = [e| $(cnv1 d) ^ $(fdesc_to_code desc)|]++cnv1 (FD_lit str) = [e| lit str|]+cnv1 FD_int       = [e| int  |]+cnv1 FD_str       = [e| str  |]+cnv1 FD_any       = [e| anys |]++spec :: String -> ExpQ+spec = fdesc_to_code . convert_to_fdesc++show_code cde = runQ cde >>= putStrLn . pprint++tc1 = show_code . spec $ "abc"+-- PrintScanF.lit ['a', 'b', 'c']++tc2 = show_code . spec $ "Hello %s!"+-- PrintScanF.lit "Hello " PrintScanF.^ +--       (TotalPrintF.str PrintScanF.^ PrintScanF.lit ['!'])+++-- A very simple language of format descriptors++data FDesc = FD_lit String | FD_str | FD_int | FD_any deriving (Eq, Show)++-- Convert "insert %s here" into +-- [FD_lit "insert ", FD_str, FD_lit " here"]+convert_to_fdesc :: String -> [FDesc]+convert_to_fdesc str = +    case break (=='%') str of+      (s1,"") -> make_lit s1+      (s1,'%':'s':rest) -> make_lit s1 ++ FD_str : convert_to_fdesc rest+      (s1,'%':'a':rest) -> make_lit s1 ++ FD_any : convert_to_fdesc rest+      (s1,'%':'d':rest) -> make_lit s1 ++ FD_int : convert_to_fdesc rest+      (_,s2) -> error $ "bad descriptor: " ++ take 5 s2+ where+ make_lit "" = []+ make_lit str = [FD_lit str]++test_cvf = and [+    convert_to_fdesc "Simple lit" ==+       [FD_lit "Simple lit"],+    convert_to_fdesc "%s insert" ==+       [FD_str,FD_lit " insert"],+    convert_to_fdesc "insert %s here" ==+    [FD_lit "insert ",FD_str,FD_lit " here"],+    convert_to_fdesc "The value of %s is %d" ==+    [FD_lit "The value of ",FD_str,FD_lit " is ",FD_int]+    ]
liboleg.cabal view
@@ -1,5 +1,5 @@ name:           liboleg-version:        0.1.1+version:        0.2 license:        BSD3 license-file:   LICENSE author:         Oleg Kiselyov@@ -17,7 +17,8 @@             base < 4,             containers,             mtl,-            unix+            unix,+            template-haskell      exposed-modules:             Data.FDList@@ -42,6 +43,9 @@              Text.PrintScan             Text.PrintScanF+            Text.GenPrintF+            Text.TotalPrintF+            Text.TFTest              System.SysOpen             System.IterateeM