我知道有一个GHC扩展名,OverloadedStrings
它允许字符串文字(由分隔"
)变成多态的,类似于数字文字的内置行为。
我的问题是:是否存在GHC扩展,该扩展允许单字符文字(以分隔'
)以类似的方式变为多态?
不是从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|é|]:75:12: error: • asciiByte: expects a single ascii character, got é • In the quasi-quotation: [asciiByte|é|] ghci> [asciiByte|abc|] :76:12: error: • asciiByte: expects a single ascii character, got abc • In the quasi-quotation: [asciiByte|abc|]
没有。
让我通过对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 ) }
(https://github.com/ghc/ghc/blob/c2991f16cb6f5b4e7cff46a394dda4247d973f44/compiler/rename/RnExpr.hs#L152)
您会看到字符串有特殊处理,但其他形式的文字则没有。最后一个子句用于根据原始Haskell标准重载的文字,正如我们在解析器的以下几行中所看到的:
| literal { ECP $ mkHsLitPV $! $1 } -- This will enable overloaded strings permanently. Normally the renamer turns HsString -- into HsOverLit when -foverloaded-strings is on. -- | STRING { sL (getLoc $1) (HsOverLit $! mkHsIsString (getSTRINGs $1) -- (getSTRING $1) noExt) } | INTEGER { ECP $ mkHsOverLitPV (sL1 $1 $ mkHsIntegral (getINTEGER $1)) } | RATIONAL { ECP $ mkHsOverLitPV (sL1 $1 $ mkHsFractional (getRATIONAL $1)) }
(https://github.com/ghc/ghc/blob/c2991f16cb6f5b4e7cff46a394dda4247d973f44/compiler/parser/Parser.y#L2793)
…
literal :: { Located (HsLit GhcPs) } : CHAR { sL1 $1 $ HsChar (getCHARs $1) $ getCHAR $1 } | STRING { sL1 $1 $ HsString (getSTRINGs $1) $ getSTRING $1 } | PRIMINTEGER { sL1 $1 $ HsIntPrim (getPRIMINTEGERs $1) $ getPRIMINTEGER $1 } | PRIMWORD { sL1 $1 $ HsWordPrim (getPRIMWORDs $1) $ getPRIMWORD $1 } | PRIMCHAR { sL1 $1 $ HsCharPrim (getPRIMCHARs $1) $ getPRIMCHAR $1 } | PRIMSTRING { sL1 $1 $ HsStringPrim (getPRIMSTRINGs $1) $ getPRIMSTRING $1 } | PRIMFLOAT { sL1 $1 $ HsFloatPrim noExt $ getPRIMFLOAT $1 } | PRIMDOUBLE { sL1 $1 $ HsDoublePrim noExt $ getPRIMDOUBLE $1 }
(https://github.com/ghc/ghc/blob/c2991f16cb6f5b4e7cff46a394dda4247d973f44/compiler/parser/Parser.y#L3708)