模板Haskell中带单引号的名称

yruzcnhs  于 2022-11-14  发布在  其他
关注(0)|答案(1)|浏览(169)

通常,在使用Template Haskell时,绑定和数据构造函数的名称是通过在它们前面加上单引号来引用的:

showName, justName :: Name
showName = 'show
justName = 'Just

不幸的是,这对第二个字符是单引号的名字不起作用,因为两个单引号之间有一个字符会被解释为字符文字。我该如何解决这个问题?

ymdaylpp

ymdaylpp1#

编辑:看来用户指南关于没有转义机制的说法是错误的!你可以在最初的单引号后面加一个空格。所以......不要使用下面的方法。
可以使用表达式引用和伪Quote示例来解决此限制。

{-# LANGUAGE DerivingVia #-}

module ExtractName (extractName) where
import Data.Functor.Identity
import GHC.Stack
import Language.Haskell.TH.Syntax

extractName :: HasCallStack => Id Exp -> Name
extractName m = case unId m of
  VarE x -> x
  ConE x -> x
  _ -> withFrozenCallStack $ error extractNameError

newtype Id a = Id {unId :: a}
  deriving (Functor, Applicative, Monad) via Identity

-- This is bogus, but good enough for what we're doing.
instance Quote Id where
  newName _ = withFrozenCallStack $ error extractNameError

extractNameError :: String
extractNameError =
  "extractName: the argument must be an expression quote containing a\n"
    ++ "single bare name, such as [| f'1 |]"

现在你可以写,例如,

f' :: Int
data Foo = B'ar

f'Name, b'arName :: Name
f'Name = extractName [| f' |]
b'arName = extractName [| B'ar |]

这是如何工作的?一个表达式引号将在实现Quote的任意单子中产生Exp。一般来说,对表达式引号进行反糖化可能需要newName方法,来对let和lambda表达式进行反糖化。然而,它 * 不 * 需要newName来对一个普通的旧绑定或数据构造函数进行反糖化。例如,一种类型,它可以用于我们需要的带引号的表达式。一旦我们打开表达式,我们就可以从中提取名称。

相关问题