Skip to content

Instantly share code, notes, and snippets.

@kana-sama
Last active March 2, 2022 14:49
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kana-sama/a97603265fbaa0aba9f16809d535029c to your computer and use it in GitHub Desktop.
Save kana-sama/a97603265fbaa0aba9f16809d535029c to your computer and use it in GitHub Desktop.
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
import Data.Kind
import Data.Proxy
import GHC.TypeLits
data FormatItem = FInt | FString | FChar Char
type Format = [FormatItem]
type ParseFormat :: Symbol -> Format
type ParseFormat s = ParseHole (UnconsSymbol s)
type ParseHole :: Maybe (Char, Symbol) -> Format
type family ParseHole ms where
ParseHole Nothing = '[]
ParseHole (Just '( '%', s)) = ParseHoleType (UnconsSymbol s)
ParseHole (Just '( c, s)) = FChar c : ParseFormat s
type ParseHoleType :: Maybe (Char, Symbol) -> Format
type family ParseHoleType ms where
ParseHoleType Nothing = '[FChar '%']
ParseHoleType (Just '( 's', s)) = FString : ParseFormat s
ParseHoleType (Just '( 'd', s)) = FInt : ParseFormat s
ParseHoleType (Just '(c, s)) = FChar '%' : FChar c : ParseFormat s
class FormatF (f :: Format) where
type FormatToType f
toFunction :: String -> FormatToType f
instance FormatF f => FormatF (FInt : f) where
type FormatToType (FInt : f) = Int -> FormatToType f
toFunction str = \i -> toFunction @f (str ++ show i)
instance FormatF f => FormatF (FString : f) where
type FormatToType (FString : f) = String -> FormatToType f
toFunction str = \s -> toFunction @f (str ++ s)
instance (KnownChar c, FormatF f) => FormatF (FChar c : f) where
type FormatToType (FChar c : f) = FormatToType f
toFunction str = toFunction @f (str ++ [charVal (Proxy @c)])
instance FormatF '[] where
type FormatToType '[] = String
toFunction str = str
formatf :: forall s f. f ~ ParseFormat s => FormatF f => FormatToType f
formatf = toFunction @f ""
main = do
putStrLn (formatf @"hello %s with id=%d" "kana" 10)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment