是否有用于启用重载字符文字的 GHC 扩展?
Is there a GHC extension for enabling overloaded character literals?
我知道有一个 GHC 扩展 OverloadedStrings
,它允许 字符串文字 (由 "
分隔)变成多态的,类似于数字文字的内置行为。
我的问题是:是否有 GHC 扩展允许 单字符文字 (由 '
分隔)以类似的方式变成多态的?
没有
让我通过对 GHC 源代码的一些探索来回答这个问题:
这是重命名器中 OverloadedString
生效的代码:
rnExpr (HsLit x lit@(HsString src s))
= do { opt_OverloadedStrings <- xoptM LangExt.OverloadedStrings
; if opt_OverloadedStrings then
rnExpr (HsOverLit x (mkHsIsString src s))
else do {
; rnLit lit
; return (HsLit x (convertLit lit), emptyFVs) } }
rnExpr (HsLit x lit)
= do { rnLit lit
; return (HsLit x(convertLit lit), emptyFVs) }
rnExpr (HsOverLit x lit)
= do { ((lit', mb_neg), fvs) <- rnOverLit lit -- See Note [Negative zero]
; case mb_neg of
Nothing -> return (HsOverLit x lit', fvs)
Just neg -> return (HsApp x (noLoc neg) (noLoc (HsOverLit x lit'))
, fvs ) }
您看到对字符串有特殊处理,但对其他形式的文字没有。最后一个子句用于根据原始 Haskell 标准重载的文字,正如我们在解析器的这些行中看到的那样:
| literal { ECP $ mkHsLitPV $! }
-- This will enable overloaded strings permanently. Normally the renamer turns HsString
-- into HsOverLit when -foverloaded-strings is on.
-- | STRING { sL (getLoc ) (HsOverLit $! mkHsIsString (getSTRINGs )
-- (getSTRING ) noExt) }
| INTEGER { ECP $ mkHsOverLitPV (sL1 $ mkHsIntegral (getINTEGER )) }
| RATIONAL { ECP $ mkHsOverLitPV (sL1 $ mkHsFractional (getRATIONAL )) }
…
literal :: { Located (HsLit GhcPs) }
: CHAR { sL1 $ HsChar (getCHARs ) $ getCHAR }
| STRING { sL1 $ HsString (getSTRINGs )
$ getSTRING }
| PRIMINTEGER { sL1 $ HsIntPrim (getPRIMINTEGERs )
$ getPRIMINTEGER }
| PRIMWORD { sL1 $ HsWordPrim (getPRIMWORDs )
$ getPRIMWORD }
| PRIMCHAR { sL1 $ HsCharPrim (getPRIMCHARs )
$ getPRIMCHAR }
| PRIMSTRING { sL1 $ HsStringPrim (getPRIMSTRINGs )
$ getPRIMSTRING }
| PRIMFLOAT { sL1 $ HsFloatPrim noExt $ getPRIMFLOAT }
| PRIMDOUBLE { sL1 $ HsDoublePrim noExt $ getPRIMDOUBLE }
从 GHC 8.8 开始还没有,但您可以使用 QuasiQuotes
扩展来获得更多。这是一个仅接受 ascii 字符并将其转换为其字节表示的准引号示例。
import Language.Haskell.TH
import Language.Haskell.TH.Quote
import Language.Haskell.TH.Syntax
import Data.Word (Word8)
import Data.Char (isAscii)
asciiByte :: QuasiQuoter
asciiByte = QuasiQuoter
{ quoteExp = \str -> case str of
[c] | isAscii c -> lift (fromIntegral (fromEnum c) :: Word8)
_ -> fail ("asciiByte: expects a single ascii character, got " ++ str)
, quotePat = \_ -> fail "asciiByte: only available for expressions"
, quoteType = \_ -> fail "asciiByte: only available for expressions"
, quoteDec = \_ -> fail "asciiByte: only available for expressions"
}
然后,您可以将其用作:
ghci> [asciiByte|a|]
97
ghci> [asciiByte|é|]
<interactive>:75:12: error:
• asciiByte: expects a single ascii character, got é
• In the quasi-quotation: [asciiByte|é|]
ghci> [asciiByte|abc|]
<interactive>:76:12: error:
• asciiByte: expects a single ascii character, got abc
• In the quasi-quotation: [asciiByte|abc|]
我知道有一个 GHC 扩展 OverloadedStrings
,它允许 字符串文字 (由 "
分隔)变成多态的,类似于数字文字的内置行为。
我的问题是:是否有 GHC 扩展允许 单字符文字 (由 '
分隔)以类似的方式变成多态的?
没有
让我通过对 GHC 源代码的一些探索来回答这个问题:
这是重命名器中 OverloadedString
生效的代码:
rnExpr (HsLit x lit@(HsString src s))
= do { opt_OverloadedStrings <- xoptM LangExt.OverloadedStrings
; if opt_OverloadedStrings then
rnExpr (HsOverLit x (mkHsIsString src s))
else do {
; rnLit lit
; return (HsLit x (convertLit lit), emptyFVs) } }
rnExpr (HsLit x lit)
= do { rnLit lit
; return (HsLit x(convertLit lit), emptyFVs) }
rnExpr (HsOverLit x lit)
= do { ((lit', mb_neg), fvs) <- rnOverLit lit -- See Note [Negative zero]
; case mb_neg of
Nothing -> return (HsOverLit x lit', fvs)
Just neg -> return (HsApp x (noLoc neg) (noLoc (HsOverLit x lit'))
, fvs ) }
您看到对字符串有特殊处理,但对其他形式的文字没有。最后一个子句用于根据原始 Haskell 标准重载的文字,正如我们在解析器的这些行中看到的那样:
| literal { ECP $ mkHsLitPV $! }
-- This will enable overloaded strings permanently. Normally the renamer turns HsString
-- into HsOverLit when -foverloaded-strings is on.
-- | STRING { sL (getLoc ) (HsOverLit $! mkHsIsString (getSTRINGs )
-- (getSTRING ) noExt) }
| INTEGER { ECP $ mkHsOverLitPV (sL1 $ mkHsIntegral (getINTEGER )) }
| RATIONAL { ECP $ mkHsOverLitPV (sL1 $ mkHsFractional (getRATIONAL )) }
…
literal :: { Located (HsLit GhcPs) }
: CHAR { sL1 $ HsChar (getCHARs ) $ getCHAR }
| STRING { sL1 $ HsString (getSTRINGs )
$ getSTRING }
| PRIMINTEGER { sL1 $ HsIntPrim (getPRIMINTEGERs )
$ getPRIMINTEGER }
| PRIMWORD { sL1 $ HsWordPrim (getPRIMWORDs )
$ getPRIMWORD }
| PRIMCHAR { sL1 $ HsCharPrim (getPRIMCHARs )
$ getPRIMCHAR }
| PRIMSTRING { sL1 $ HsStringPrim (getPRIMSTRINGs )
$ getPRIMSTRING }
| PRIMFLOAT { sL1 $ HsFloatPrim noExt $ getPRIMFLOAT }
| PRIMDOUBLE { sL1 $ HsDoublePrim noExt $ getPRIMDOUBLE }
从 GHC 8.8 开始还没有,但您可以使用 QuasiQuotes
扩展来获得更多。这是一个仅接受 ascii 字符并将其转换为其字节表示的准引号示例。
import Language.Haskell.TH
import Language.Haskell.TH.Quote
import Language.Haskell.TH.Syntax
import Data.Word (Word8)
import Data.Char (isAscii)
asciiByte :: QuasiQuoter
asciiByte = QuasiQuoter
{ quoteExp = \str -> case str of
[c] | isAscii c -> lift (fromIntegral (fromEnum c) :: Word8)
_ -> fail ("asciiByte: expects a single ascii character, got " ++ str)
, quotePat = \_ -> fail "asciiByte: only available for expressions"
, quoteType = \_ -> fail "asciiByte: only available for expressions"
, quoteDec = \_ -> fail "asciiByte: only available for expressions"
}
然后,您可以将其用作:
ghci> [asciiByte|a|]
97
ghci> [asciiByte|é|]
<interactive>:75:12: error:
• asciiByte: expects a single ascii character, got é
• In the quasi-quotation: [asciiByte|é|]
ghci> [asciiByte|abc|]
<interactive>:76:12: error:
• asciiByte: expects a single ascii character, got abc
• In the quasi-quotation: [asciiByte|abc|]