Skip to content

Instantly share code, notes, and snippets.

@monadplus
Last active June 30, 2022 21:05
Show Gist options
  • Save monadplus/7378a42341b5f809d96d9df4655da864 to your computer and use it in GitHub Desktop.
Save monadplus/7378a42341b5f809d96d9df4655da864 to your computer and use it in GitHub Desktop.
Haskell: type-safe sprintf
-- Source: Fun with Type Functions
data L
data V a
data f1 :<>: f2
type Parser a = String -> [(a, String)]
type Printer a = a -> String
data F f where
L :: String -> F L
V :: Parser a -> Printer a -> F (V a)
(:<>:) :: F f1 -> F f2 -> F (f1 :<>: f2)
infixr 7 :<>:
instance IsString (F L) where
fromString = L
type Sprintf f = TPrinter f String
type family TPrinter f x where
TPrinter L x = x
TPrinter (V a) x = a -> x
TPrinter (f1 :<>: f2) x = TPrinter f1 (TPrinter f2 x)
sprintf :: F f -> Sprintf f
sprintf fmt = printer fmt id
where
printer :: F f -> (String -> a) -> TPrinter f a
printer (L str) k = k str
printer (V _ show) k = \a -> k $ show a
printer (f1 :<>: f2) k = printer f1 $ \str1 -> printer f2 $ \str2 -> k (str1 ++ str2)
d# :: F (V Int)
d# = V reads show
f# :: F (V Double)
f# = V reads show
main :: IO ()
main = do
print $
sprintf ("I am " :<>: d# :<>: " years old.") 26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment