6

我知道有一个 GHC 扩展,OverloadedStrings它允许字符串文字(由 分隔")变得多态,类似于数字文字的内置行为。

我的问题是:是否有一个 GHC 扩展允许单字符文字(由 分隔')以类似的方式变得多态?

4

2 回答 2

8

不是从 GHC 8.8 开始,但您可以使用该QuasiQuotes扩展来获得相当大的帮助。这是一个 quasiquote 的示例,它只接受一个 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|]

于 2019-11-16T12:55:51.083 回答
6

不。

让我通过对 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

…</p>

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

于 2019-11-16T12:47:24.740 回答