packages feed

typelits-printf 0.1.1.0 → 0.2.0.0

raw patch · 5 files changed

+106/−367 lines, 5 filesdep −vinylPVP ok

version bump matches the API change (PVP)

Dependencies removed: vinyl

API changes (from Hackage documentation)

- GHC.TypeLits.Printf: PP :: a -> PP (c :: SChar)
- GHC.TypeLits.Printf: [RNil] :: forall u (a :: u -> Type). Rec a ('[] :: [u])
- GHC.TypeLits.Printf: data PP (c :: SChar)
- GHC.TypeLits.Printf: data Rec (a :: u -> Type) (b :: [u])
- GHC.TypeLits.Printf: infixr 7 :%
- GHC.TypeLits.Printf: pattern (:%) :: () => FormatType c a => a -> FormatArgs cs -> FormatArgs (c : cs)
- GHC.TypeLits.Printf: pprintf :: forall str ps. (RPrintf str ps, RecordCurry ps) => CurriedF PP ps String
- GHC.TypeLits.Printf: pprintf_ :: forall str ps p. (RPrintf str ps, RecordCurry ps) => p str -> CurriedF PP ps String
- GHC.TypeLits.Printf: rprintf :: forall str ps. RPrintf str ps => FormatArgs ps -> String
- GHC.TypeLits.Printf: rprintf_ :: RPrintf str ps => p str -> FormatArgs ps -> String
- GHC.TypeLits.Printf: type FormatArgs = Rec PP
- GHC.TypeLits.Printf.Internal: PP :: a -> PP (c :: SChar)
- GHC.TypeLits.Printf.Internal: class RFormat (ffs :: [Either Symbol FieldFormat]) (ps :: [SChar]) | ffs -> ps
- GHC.TypeLits.Printf.Internal: class RPrintf (str :: Symbol) ps
- GHC.TypeLits.Printf.Internal: data PP (c :: SChar)
- GHC.TypeLits.Printf.Internal: instance (Data.Symbol.Utils.Listify str lst, ffs GHC.Types.~ GHC.TypeLits.Printf.Parse.ParseFmtStr_ lst, GHC.TypeLits.Printf.Internal.RFormat ffs ps) => GHC.TypeLits.Printf.Internal.RPrintf str ps
- GHC.TypeLits.Printf.Internal: instance (GHC.TypeLits.KnownSymbol str, GHC.TypeLits.Printf.Internal.RFormat ffs ps) => GHC.TypeLits.Printf.Internal.RFormat ('Data.Either.Left str : ffs) ps
- GHC.TypeLits.Printf.Internal: instance (GHC.TypeLits.Printf.Parse.Reflect ff, ff GHC.Types.~ 'GHC.TypeLits.Printf.Parse.FF f w p m c, GHC.TypeLits.Printf.Internal.FormatType c a, GHC.TypeLits.Printf.Internal.FormatFun ffs fun) => GHC.TypeLits.Printf.Internal.FormatFun ('Data.Either.Right ff : ffs) (a -> fun)
- GHC.TypeLits.Printf.Internal: instance (GHC.TypeLits.Printf.Parse.Reflect ff, ff GHC.Types.~ 'GHC.TypeLits.Printf.Parse.FF f w p m c, GHC.TypeLits.Printf.Internal.RFormat ffs ps) => GHC.TypeLits.Printf.Internal.RFormat ('Data.Either.Right ff : ffs) (c : ps)
- GHC.TypeLits.Printf.Internal: instance (a GHC.Types.~ GHC.Types.Char) => GHC.TypeLits.Printf.Internal.FormatFun '[] [a]
- GHC.TypeLits.Printf.Internal: instance GHC.TypeLits.Printf.Internal.RFormat '[] '[]
- GHC.TypeLits.Printf.Internal: rformat :: RFormat ffs ps => p ffs -> FormatArgs ps -> ShowS
- GHC.TypeLits.Printf.Internal: rprintf_ :: RPrintf str ps => p str -> FormatArgs ps -> String
- GHC.TypeLits.Printf.Internal: type FormatArgs = Rec PP
+ GHC.TypeLits.Printf.Internal: instance (a GHC.Types.~ GHC.Base.String) => GHC.TypeLits.Printf.Internal.FormatFun '[] a
+ GHC.TypeLits.Printf.Internal: instance (afun GHC.Types.~ (arg -> fun), GHC.TypeLits.Printf.Parse.Reflect ff, ff GHC.Types.~ 'GHC.TypeLits.Printf.Parse.FF f w p m c, GHC.TypeLits.Printf.Internal.FormatType c arg, GHC.TypeLits.Printf.Internal.FormatFun ffs fun) => GHC.TypeLits.Printf.Internal.FormatFun ('Data.Either.Right ff : ffs) afun

Files

CHANGELOG.md view
@@ -1,12 +1,24 @@ Changelog ========= +Version 0.2.0.0+---------------++*February 26, 2020*++<https://github.com/mstksg/typelits-printf/releases/tag/v0.2.0.0>++*   Following <https://github.com/mstksg/typelits-printf/pull/3>, we can now+    get "all three" benefits with `printf`.  This version removes all traces+    of `pprintf`, `PP`, and `rprintf`, making `printf` the official+    one-size-fits-all function. Thanks @kcsongor!+ Version 0.1.1.0 ---------------  *February 26, 2020* -<https://github.com/mstksg/symbols-printf/releases/tag/v0.1.1.0>+<https://github.com/mstksg/typelits-printf/releases/tag/v0.1.1.0>  *   Major bug fix in parser (thanks @kcsongor) @@ -15,6 +27,6 @@  *February 25, 2020* -<https://github.com/mstksg/symbols-printf/releases/tag/v0.1.0.0>+<https://github.com/mstksg/typelits-printf/releases/tag/v0.1.0.0>  *   Initial release
README.md view
@@ -11,84 +11,63 @@  An extensible and type-safe printf from parsing GHC TypeLits Symbol literals, matching the semantics of *[Text.Printf][]* in *base*.  The difference is that-the variants here will always fail to compile if given arguments of the wrong-type (or too many or too little arguments). Most of the variants also provide-useful type feedback, telling you the type of arguments it expects and how many+your `printf`s will always fail to compile if given arguments of the wrong type+(or too many or too little arguments).  It also allows you to use types to help+your development, by telling you the type of arguments it expects and how many when queried with `:t` or with typed holes.  [Text.Printf]: https://hackage.haskell.org/package/base/docs/Text-Printf.html -There are three main calling conventions offered:- ```haskell ghci> putStrLn $ printf @"You have %.2f dollars, %s" 3.62 "Luigi" You have 3.62 dollars, Luigi--ghci> putStrLn $ pprintf @"You have %.2f dollars, %s" (PP 3.62) (PP "Luigi")-You have 3.62 dollars, Luigi--ghci> putStrLn $ rprintf @"You have %.2f dollars, %s" (3.62 :% "Luigi" :% RNil)-You have 3.62 dollars, Luigi ``` -Comparing their types:+Looking at its type:  ```haskell-ghci> :t printf @"You have %.2f dollars, %s" 3.62 "Luigi"-FormatFun '[ .... ] fun => fun--ghci> :t pprintf @"You have %.2f dollars, %s" 3.62 "Luigi"-PP "f" -> PP "s" -> String--ghci> :t rprintf @"You have %.2f dollars, %s" 3.62 "Luigi"-FormatArgs '["f", "s"] -> String+ghci> :t printf @"You have %.2f dollars, %s"+(FormatType "f" arg1, FormatType "s" arg2)+  => arg1 -> arg2 -> String ``` -*   The type of `printf` doesn't tell you immediately what you-    you need.  However, if you do try to use it, the type errors will guide you-    along the way, iteratively.--    ```haskell-    ghci> printf @"You have %.2f dollars, %s"-    -- ERROR: Call to printf missing argument fulfilling "%.2f"-    -- Either provide an argument or rewrite the format string to not expect-    -- one.+It tells you that the result is an `arg1 -> arg2 -> String`: take two+arguments, and return a `String`.  The first argument must be an instance of+`FormatType "f"` (things that can be formatted by `%f`) and the second argument+must be an instance of `FormatType "s"` (things that can be formatted by `%s`). -    ghci> printf @"You have %.2f dollars, %s" 3.62-    -- ERROR: Call to printf missing argument fulfilling "%s"-    -- Either provide an argument or rewrite the format string to not expect-    -- one.+We can see this in action by progressively applying arguments: -    ghci> printf @"You have %.2f dollars, %s" 3.62 "Luigi"-    You have 3.62 dollars, Luigi+```haskell+ghci> :t printf @"You have %.2f dollars, %s" 3.62+FormatType "s" arg1 => arg1 -> String -    ghci> printf @"You have %.2f dollars, %s" 3.62 "Luigi" 72-    -- ERROR: An extra argument of type Integer was given to a call to printf-    -- Either remove the argument, or rewrite the format string to include the-    -- appropriate hole.-    ```+ghci> :t printf @"You have %.2f dollars, %s" 3.62 "Luigi"+String+``` -*   For `pprintf`, it shows you need two arguments: A `PP "f"` (which is a-    value that supports being formatted by `f`) like `PP 3.62`, and a `PP "s"`,-    like `PP "Luigi"`.+The type errors for forgetting to apply an argument (or applying too many+arguments) are pretty clear: -*   `rprintf` tells you you need a two-item hlist (from "Data.Vinyl.Core"),-    where the first item implements `f` and the second item implements `s`:-    `3.62 :% "Luigi" :% RNil` will do.+```haskell+ghci> putStrLn $ printf @"You have %.2f dollars, %s"+-- ERROR: Call to printf missing argument fulfilling "%.2f"+-- Either provide an argument or rewrite the format string to not expect+-- one. -The following table summarizes the features and drawbacks of each-method:+ghci> putStrLn $ printf @"You have %.2f dollars, %s" 3.62+-- ERROR: Call to printf missing argument fulfilling "%s"+-- Either provide an argument or rewrite the format string to not expect+-- one. -| Method    | True Polyarity   | Naked Arguments    | Type feedback        |-| --------- | ---------------- | ------------------ | -------------------- |-| `printf`  | Yes              | Yes                | Partial (via errors) |-| `pprintf` | Yes              | No (requires `PP`) | Yes                  |-| `rprintf` | No (HList-based) | Yes                | Yes                  |+ghci> putStrLn $ printf @"You have %.2f dollars, %s" 3.62 "Luigi"+You have 3.62 dollars, Luigi -*Ideally* we would have a solution that has all three.  However, as of now, we-have a "pick two" sort of situation.  Suggestions are definitely welcome,-however, if you find something that satisfies all three benefits while still-allowing for polymorphism!+ghci> putStrLn $ printf @"You have %.2f dollars, %s" 3.62 "Luigi" 72+-- ERROR: An extra argument of type Integer was given to a call to printf+-- Either remove the argument, or rewrite the format string to include the+-- appropriate hole.+```  You can extend functionality with formatting for your own types by providing instances of `FormatType`.@@ -97,7 +76,7 @@  For medium-length or long strings, the parsing can be fairly slow and cause slow compile times.  This might be due to the underlying mechanism that the-*[symbols][]* package exploits.+*[symbols][]* package exploits...or just GHC performance issues in general.  [symbols]: https://hackage.haskell.org/package/symbols 
src/GHC/TypeLits/Printf.hs view
@@ -27,102 +27,30 @@ -- -- An extensible and type-safe printf from parsing GHC TypeLits Symbol -- literals, matching the semantics of 'P.printf' from "Text.Printf" in--- /base/.  The difference is that the variants here will always fail to+-- /base/.  The difference is that your 'printf's will always fail to -- compile if given arguments of the wrong type (or too many or too little--- arguments).  Most of the variants also provide useful type feedback,--- telling you the type of arguments it expects and how many when queried--- with @:t@ or with typed holes.  See documentation in "Text.Printf" for--- details on how this formats items of various types, and the differences--- with C @printf(3)@.------ There are three main calling conventions supported:------ >>> putStrLn $ printf @"You have %.2f dollars, %s" 3.62 "Luigi"--- You have 3.62 dollars, Luigi--- >>> putStrLn $ pprintf @"You have %.2f dollars, %s" (PP 3.62) (PP "Luigi")--- You have 3.62 dollars, Luigi--- >>> putStrLn $ rprintf @"You have %.2f dollars, %s" (3.62 :% "Luigi" :% RNil)--- You have 3.62 dollars, Luigi------ Now comparing their types:------ >>> :t printf @"You have %.2f dollars, %s" 3.62 "Luigi"--- FormatFun '[ .... ] fun => fun--- >>> :t pprintf @"You have %.2f dollars, %s" 3.62 "Luigi"--- PP "f" -> PP "s" -> String--- >>> :t rprintf @"You have %.2f dollars, %s" 3.62 "Luigi"--- FormatArgs '["f", "s"] -> String------ *   The type of `printf` doesn't tell you immediately what you you need.---     However, if you do try to use it, the type errors will guide you---     along the way, iteratively.------     >>> printf @"You have %.2f dollars, %s"---     -- ERROR: Call to printf missing argument fulfilling "%.2f"---     -- Either provide an argument or rewrite the format string to not expect---     -- one.------     >>> printf @"You have %.2f dollars, %s" 3.62---     -- ERROR: Call to printf missing argument fulfilling "%s"---     -- Either provide an argument or rewrite the format string to not expect---     -- one.------     >>> printf @"You have %.2f dollars, %s" 3.62 "Luigi"---     You have 3.62 dollars, Luigi------     >>> printf @"You have %.2f dollars, %s" 3.62 "Luigi" 72---     -- ERROR: An extra argument of type Integer was given to a call to printf---     -- Either remove the argument, or rewrite the format string to include the---     -- appropriate hole.------ *   For 'pprintf', it shows you need two arguments: A @'PP' "f"@ (which---     is a value that supports being formatted by @f@) like @PP 3.62@, and---     a @'PP' "s"@, like @PP "Luigi"@.------ *   'rprintf' tells you you need a two-item hlist (from---     "Data.Vinyl.Core"), where the first item implements @f@ and the---     second item implements @s@: @3.62 ':%' "Luigi" :% 'RNil'@ will do.------ The following table summarizes the features and drawbacks of each--- method:------ +-----------+------------------+--------------------+----------------------+--- | Method    | True Polyarity   | Naked Arguments    | Type feedback        |--- +===========+==================+====================+======================+--- | 'printf'  | Yes              | Yes                | Partial (via errors) |--- +-----------+------------------+--------------------+----------------------+--- | 'pprintf' | Yes              | No (requires 'PP') | Yes                  |--- +-----------+------------------+--------------------+----------------------+--- | 'rprintf' | No (HList-based) | Yes                | Yes                  |--- +-----------+------------------+--------------------+----------------------++-- arguments).  It also allows you to use types to help your development,+-- by telling you the type of arguments it expects and how many when+-- queried with @:t@ or with typed holes. See documentation in+-- "Text.Printf" for details on how this formats items of various types,+-- and the differences with C @printf(3)@. ----- /Ideally/ we would have a solution that has all three.  However, as of--- now, we have a "pick two" sort of situation.  Suggestions are definitely--- welcome, however, if you find something that satisfies all three--- benefits while still allowing for polymorphism!+-- See 'printf' for the main function. ----- You can extend functionality with formatting for your own types by--- providing instances of @FormatType@.+-- You can extend functionality with formatting for your own types by providing+-- instances of 'FormatType'. -- -- Also in this module is 'pfmt', which allows you to format individual -- items according to a single format specifier.-+-- module GHC.TypeLits.Printf (-  -- * Formattable things-    FormatType(..)-  , SChar   -- * Printf-  -- ** Unguarded polyarity-  , printf, printf_+    printf, printf_   , PHelp, pHelp   , FormatFun-  -- ** Guarded polyarity-  , pprintf-  , pprintf_-  , PP(..)-  -- ** List-based polyarity-  , rprintf, rprintf_-  , Rec((:%), RNil), FormatArgs+  -- * Formattable things+  , FormatType(..)+  , SChar   -- * Single item   , pfmt   , PFmt@@ -130,125 +58,56 @@   ) where  import           Data.Proxy-import           Data.Vinyl-import           Data.Vinyl.Curry import           GHC.TypeLits.Printf.Internal --- | Type-safe printf with faked polyarity.  Pass in a "list" of arguments--- (using ':%' and 'RNil'), instead of as multiple arguments.  Call it like--- @'rprintf' \@"you have %.02f dollars, %s"@.------ >>> :t rprintf @"You have %.2f dollars, %s"--- FormatArgs '["f", "s"] -> String------ This means that it is expecting something that can be printed with @f@--- and something that can be printed with @s@.  We can provide a 'Double'--- and a 'String':+-- | "Type-safe printf". Call it like @'printf' \@"you have %.02f dollars, %s"@. ----- >>> putStrLn $ rprintf @"You have %.2f dollars, %s" (3.62 ':%' "Luigi" :% 'RNil')+-- >>> putStrLn $ printf @"You have %.2f dollars, %s" 3.62 "Luigi" -- You have 3.62 dollars, Luigi ----- See 'pprintf' for a version with true polyarity and good clear types,--- but requires wrapping its arguments, and 'printf' for a version with--- true polyarity but less clear types.  Also see top-level module--- documentation  "GHC.TypeLits.Printf" for a more comprehensive summary.-rprintf :: forall str ps. RPrintf str ps => FormatArgs ps -> String-rprintf = rprintf_ (Proxy @str)---- | Pattern and constructor allowing you to construct a 'FormatArgs'.------ To construct a @'FormatArgs' '["f", "s"]@, for instance, you need to--- give a value formattable by @f@ and a value formattable by @s@, given--- like a linked list, with ':%' for cons and 'RNil' for nil.------ @--- 3.62 ':%' "Luigi" :% 'RNil'--- @------ (This should evoke the idea of of @3.62 : "Luigi" : []@, even though the--- latter is not possible in Haskell)-pattern (:%) :: () => FormatType c a => a -> FormatArgs cs -> FormatArgs (c ': cs)-pattern x :% xs = PP x :& xs-infixr 7 :%-{-# COMPLETE (:%) #-}---- | A version of 'pprintf' taking an explicit proxy, which allows usage--- without /TypeApplications/------ >>> :t pprintf_ (Proxy :: Proxy "You have %.2f dollars, %s")--- PP "f" -> PP "s" -> String-pprintf_ :: forall str ps p. (RPrintf str ps, RecordCurry ps) => p str -> CurriedF PP ps String-pprintf_ p = rcurry @ps (rprintf_ p)---- | Type-safe printf with true guarded polyarity.  Call it like @'pprintf'--- \@"you have %.02f dollars, %s"@.------ A call to printf on a valid string will /always/ give a well-defined--- type for a function in return:------ >>> :t pprintf @"You have %.2f dollars, %s"--- PP "f" -> PP "s" -> String------ You can always query the type, and get a well-defined type back, which--- you can utilize using typed holes or other type-guided development--- techniques.+-- Looking at its type: ----- To give 'pprintf' its arguments, however, they must be wrapped in 'PP':+-- >>> :t printf @"You have %.2f dollars, %s"+-- (FormatType "f" arg1, FormatType "s" arg2)+--   => arg1 -> arg2 -> String ----- >>> putStrLn $ pprintf @"You have %.2f dollars, %s" (PP 3.62) (PP "Luigi")--- You have 3.62 dollars, Luigi+-- It tells you that the result is an @arg1 -> arg2 -> 'String'@: take two+-- arguments, and return a 'String'.  The first argument must be an instance of+-- @'FormatType' "f"@ (things that can be formatted by @%f@) and the second argument+-- must be an instance of @'FormatType' "s"@ (things that can be formatted by @%s@). ----- See 'printf' for a polyariadic method that doesn't require 'PP' on its--- inputs, but with a less helpful type signature, and 'rprintf' for--- a fake-polyariadic method that doesn't require 'PP', but requires--- arguments in a single list instead. Also see top-level module--- documentation  "GHC.TypeLits.Printf" for a more comprehensive summary.-pprintf :: forall str ps. (RPrintf str ps, RecordCurry ps) => CurriedF PP ps String-pprintf = pprintf_ @str @ps (Proxy @str)---- | Type-safe printf with true naked polyarity.  Call it like @'printf'--- \@"you have %.02f dollars, %s"@.+-- We can see this in action by progressively applying arguments: ----- >>> putStrLn $ printf @"You have %.2f dollars, %s" 3.62 "Luigi"--- You have 3.62 dollars, Luigi+-- >>> :t printf @"You have %.2f dollars, %s" 3.62+-- FormatType "s" arg1 => arg1 -> String+-- >>> :t printf @"You have %.2f dollars, %s" 3.62 "Luigi"+-- String ----- While the type of @'printf' \@"my fmt string"@ isn't going to be very--- helpful, the error messages should help guide you along the way:+-- The type errors for forgetting to apply an argument (or applying too many+-- arguments) are pretty clear: ----- >>> printf @"You have %.2f dollars, %s"+-- >>> putStrLn $ printf @"You have %.2f dollars, %s" -- -- ERROR: Call to printf missing argument fulfilling "%.2f" -- -- Either provide an argument or rewrite the format string to not expect -- -- one.------ >>> printf @"You have %.2f dollars, %s" 3.62+-- >>> putStrLn $ printf @"You have %.2f dollars, %s" 3.62 -- -- ERROR: Call to printf missing argument fulfilling "%s" -- -- Either provide an argument or rewrite the format string to not expect -- -- one.------ >>> printf @"You have %.2f dollars, %s" 3.62 "Luigi"+-- >>> putStrLn $ printf @"You have %.2f dollars, %s" 3.62 "Luigi" -- You have 3.62 dollars, Luigi------ >>> printf @"You have %.2f dollars, %s" 3.62 "Luigi" 72+-- >>> putStrLn $ printf @"You have %.2f dollars, %s" 3.62 "Luigi" 72 -- -- ERROR: An extra argument of type Integer was given to a call to printf -- -- Either remove the argument, or rewrite the format string to include the -- -- appropriate hole. ----- If you're having problems getting the error messages to give helpful--- feedback, try using 'pHelp':+-- If you want to see some useful error messages for feedback, 'pHelp' can+-- be useful: -- -- >>> pHelp $ printf @"You have %.2f dollars, %s" 3.62 -- -- ERROR: Call to printf missing argument fulfilling "%s" -- -- Either provide an argument or rewrite the format string to not expect -- -- one.------ 'pHelp' can give the type system the nudge it needs to provide good--- errors.------ See 'pprintf' for a version of this with nicer types and type errors,--- but requires wrapping arguments, and 'rprintf' for a version of this--- with "fake" polyarity, taking a list as input instead. Also see--- top-level module documentation  "GHC.TypeLits.Printf" for a more--- comprehensive summary. -- -- Note that this also supports the "interpret as an IO action to print out -- results" functionality that "Text.Printf" supports.  This also supports
src/GHC/TypeLits/Printf/Internal.hs view
@@ -49,10 +49,6 @@   , Demote   , Reflect(..)   , FormatType(..)-  , PP(..)-  , RPrintf(..)-  , FormatArgs-  , RFormat(..)   , Printf(..)   , FormatFun(..)   , PFmt(..)@@ -64,7 +60,6 @@ import           Data.Int import           Data.Proxy import           Data.Symbol.Utils-import           Data.Vinyl import           Data.Word import           GHC.OverloadedLabels import           GHC.TypeLits@@ -235,141 +230,36 @@ instance FormatType "v" TL.Text where     formatArg _ = P.formatArg . TL.unpack --- | Required wrapper around inputs to 'GHC.TypeLits.Printf.pprintf'--- (guarded polyarity).  See documentation for--- 'GHC.TypeLits.Printf.pprintf' for examples of usage.------ You can "wrap" any value in 'PP' as long as it can be formatted as the--- format type indicated.------ For example, to make a @'PP' "f"@, you can use @'PP' 3.5@ or @'PP'--- 94.2@, but not @'PP' (3 :: Int)@ or @'PP' "hello"@.  To make a value of--- type @'PP' c@, you must wrap a value that can be formatted via @c@.-data PP (c :: SChar) = forall a. FormatType c a => PP a---- | A heterogeneous list (from "Data.Vinyl.Core") used for calling with--- 'GHC.TypeLits.Printf.rprintf'.  Instead of supplying the inputs as--- different arguments, we can gather all the inputs into a single list to--- give to 'GHC.TypeLits.Printf.rprintf'.------ >>> :t rprintf @"You have %.2f dollars, %s"--- FormatArgs '["f", "s"] -> String------ To construct a @'FormatArgs' '["f", "s"]@, you need to give a value--- formattable by @f@ and a value formattable by @s@, given like a linked--- list, with 'GHC.TypeLits.Printf.:%' for cons and 'RNil' for nil.------ >>> putStrLn $ rprintf @"You have %.2f dollars, %s" (3.62 :% "Luigi" :% RNil)--- You have 3.62 dollars, Luigi------ (This should evoke the idea of of @3.62 : "Luigi" : []@, even though the--- latter is not possible in Haskell)-type FormatArgs = Rec PP--class RFormat (ffs :: [Either Symbol FieldFormat]) (ps :: [SChar]) | ffs -> ps where-    rformat :: p ffs -> FormatArgs ps -> ShowS--instance RFormat '[] '[] where-    rformat _ _ = id--instance (KnownSymbol str, RFormat ffs ps) => RFormat ('Left str ': ffs) ps where-    rformat _ r = showString (symbolVal (Proxy @str))-                . rformat (Proxy @ffs) r--instance (Reflect ff, ff ~ 'FF f w p m c, RFormat ffs ps) => RFormat ('Right ff ': ffs) (c ': ps) where-    rformat _ (PP x :& xs) = formatArg (Proxy @c) x ff-                           . rformat (Proxy @ffs) xs-      where-        ff = reflect (Proxy @ff)--class RPrintf (str :: Symbol) ps where-    -- | A version of 'GHC.TypeLits.Printf.rprintf' taking an explicit-    -- proxy, which allows usage without /TypeApplications/-    ---    -- >>> :t rprintf_ (Proxy :: Proxy "You have %.2f dollars, %s")-    -- FormatArgs '["f", "s"] -> String-    rprintf_ :: p str -> FormatArgs ps -> String--instance (Listify str lst, ffs ~ ParseFmtStr_ lst, RFormat ffs ps) => RPrintf str ps where-    rprintf_ _ = ($ "") . rformat (Proxy @ffs)- -- | The typeclass supporting polyarity used by -- 'GHC.TypeLits.Printf.printf'. It works in mostly the same way as -- 'P.PrintfType' from "Text.Printf", and similar the same as--- 'Data.Symbol.Examples.Printf.FormatF'.------ Ideally, you will never have to run into this typeclass or have to deal--- with it.  It will come up if you ask for the type of--- 'GHC.TypeLits.Printf.printf', or sometimes if you give the wrong number--- or type of arguments to it.------ >>> :t printf @"You have %.2f dollars, %s"--- FormatFun '[ Right ..., 'Left " dollars ", 'Right ...] fun => fun+-- 'Data.Symbol.Examples.Printf.FormatF'.  Ideally, you will never have to+-- run into this typeclass or have to deal with it directly. -- -- Every item in the first argument of 'FormatFun' is a chunk of the -- formatting string, split between format holes ('Right') and string--- chunks ('Left').  You can successively "eliminate" them by providing--- more arguments that implement each hole:------ >>> :t printf @"You have %.2f dollars, %s" 3.62--- FormatFun '[ Right ...] fun => fun------ Until you you finally fill all the holes:------ >>> :t printf @"You have %.2f dollars, %s" 3.62 "Luigi"--- FormatFun '[] t => t------ at which point you may use it as a 'String' or @'IO' ()@, in the same--- way that "Text.Printf" works.  We also support using strict 'T.Text'--- lazy 'TL.Text' as well.------ So, while it's possible to reason with this using the types, it's--- usually more difficult than with 'pprintf' and 'rprintf'.------ This is why, instead of reasoning with this using its types, it's easier--- to reason with it using the errors instead:------ >>> printf @"You have %.2f dollars, %s"--- -- ERROR: Call to printf missing argument fulfilling "%.2f"--- -- Either provide an argument or rewrite the format string to not expect--- -- one.------ >>> printf @"You have %.2f dollars, %s" 3.62--- -- ERROR: Call to printf missing argument fulfilling "%s"--- -- Either provide an argument or rewrite the format string to not expect--- -- one.------ >>> printf @"You have %.2f dollars, %s" 3.62 "Luigi"--- You have 3.62 dollars, Luigi------ >>> printf @"You have %.2f dollars, %s" 3.62 "Luigi" 72--- -- ERROR: An extra argument of type Integer was given to a call to printf--- -- Either remove the argument, or rewrite the format string to include the--- -- appropriate hole.+-- chunks ('Left'). ----- If you're having problems getting the error messages to give helpful--- feedback, try using 'pHelp':+-- If you want to see some useful error messages for feedback, 'pHelp' can+-- be useful: -- -- >>> pHelp $ printf @"You have %.2f dollars, %s" 3.62 -- -- ERROR: Call to printf missing argument fulfilling "%s" -- -- Either provide an argument or rewrite the format string to not expect -- -- one.------ 'pHelp' can give the type system the nudge it needs to provide good--- errors. class FormatFun (ffs :: [Either Symbol FieldFormat]) fun where     formatFun :: p ffs -> String -> fun --- | A useful token for helping the type system give useful errors for--- 'printf':+-- | A useful tool for helping the type system give useful errors for+-- 'GHC.TypeLits.Printf.printf': -- -- >>> printf @"You have ".2f" dollars, %s" 3.26 :: PHelp -- -- ERROR: Call to printf missing argument fulfilling "%s" -- -- Either provide an argument or rewrite the format string to not expect -- -- one. ----- Usually things should work out on their own without needing this ... but--- sometimes the type system could need a nudge.+-- Mostly useful if you want to force a useful type error to help see what+-- is going on. -- -- See also 'pHelp' newtype PHelp = PHelp {@@ -381,12 +271,12 @@     -- -- Either provide an argument or rewrite the format string to not expect     -- -- one.     ---    -- Usually things would work out on their own without needing this ...-    -- but sometimes the type system could need a nudge.+    -- Mostly useful if you want to force a useful type error to help see+    -- what is going on.     pHelp :: String   } -instance (a ~ Char) => FormatFun '[] [a] where+instance {-# INCOHERENT #-} (a ~ String) => FormatFun '[] a where     formatFun _ = id instance (a ~ Char) => FormatFun '[] PHelp where     formatFun _ = PHelp@@ -414,7 +304,7 @@ instance (KnownSymbol str, FormatFun ffs fun) => FormatFun ('Left str ': ffs) fun where     formatFun _ str = formatFun (Proxy @ffs) (str ++ symbolVal (Proxy @str)) -instance (Reflect ff, ff ~ 'FF f w p m c, FormatType c a, FormatFun ffs fun) => FormatFun ('Right ff ': ffs) (a -> fun) where+instance {-# INCOHERENT #-} (afun ~ (arg -> fun), Reflect ff, ff ~ 'FF f w p m c, FormatType c arg, FormatFun ffs fun) => FormatFun ('Right ff ': ffs) afun where     formatFun _ str x = formatFun (Proxy @ffs) (str ++ formatArg (Proxy @c) x ff "")       where         ff = reflect (Proxy @ff)@@ -449,7 +339,7 @@ instance (Listify str lst, ffs ~ ParseFmtStr_ lst, FormatFun ffs fun) => Printf str fun where     printf_ _ = formatFun (Proxy @ffs) "" --- | Utility type powering 'pfmt'.  See dcumentation for 'pfmt' for more+-- | Utility type powering 'pfmt'.  See documentation for 'pfmt' for more -- information on usage. -- -- Using /OverloadedLabels/, you never need to construct this directly@@ -460,7 +350,7 @@  -- | A version of 'mkPFmt' that takes an explicit proxy input. ----- >>> pfmt (mkPFmt_ (Proxy :: Proxy ".2f") 3.6234124+-- >>> pfmt (mkPFmt_ (Proxy :: Proxy ".2f")) 3.6234124 -- "3.62" mkPFmt_     :: forall str lst ff f w q m c p. (Listify str lst, ff ~ ParseFmt_ lst, Reflect ff, ff ~ 'FF f w q m c)@@ -510,6 +400,6 @@ -- -- (which should be possible in GHC 8.10+) ----- Note that the format string does not include the leading @%@.+-- Note that the format string should not include the leading @%@. pfmt :: forall c a. FormatType c a => PFmt c -> a -> String pfmt (PFmt ff) x = formatArg (Proxy @c) x ff ""
typelits-printf.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: b5b3f760af5c7c80862e1246320b78e43abe2900acd93e8fe21ace4920fcc4ed+-- hash: ab8bb88b98e9aefe5c55f593c26d691a8125a6014b60204b85fda8f8ea01e90b  name:           typelits-printf-version:        0.1.1.0+version:        0.2.0.0 synopsis:       Type-safe printf from parsing GHC TypeLits Symbol description:    An extensible and type-safe printf from parsing GHC TypeLits Symbol                 literals, matching the semantics of 'P.printf' from "Text.Printf" in /base/.@@ -50,5 +50,4 @@       base >=4.13 && <5     , symbols >=0.3 && <0.4     , text-    , vinyl >=0.12.1   default-language: Haskell2010