考虑以下代码:
magic :: String -> Q Exp magic s = [e| putStrLn s |]
现在,尽我所知,这实际上不应该起作用.在牛津括号内,s不在范围内.然而,上述显然完美无缺.
如果我们稍微改变这个例子,它现在可怕地破坏了:
magic :: Exp -> Q Exp magic (VarE n) = [e| putStrLn (nameBase n) |]
就像以前一样,我们有一个不在范围内的变量.而这一次,它打破了.但它没有抱怨不在范围内的变量; 相反,它抱怨一些没有实例的无证件类.
谁知道到底发生了什么?
我的模块包含定义,其中一部分是导出的(在module子句中).我也想导出Template Haskell生成的声明.但由于似乎没有办法module用TH 修改条款,我不能这样做.
是否可以指定应该导出TH生成的声明?或者也许有其他方法可以做到这一点?
我希望我的TemplateHaskell表达式(使用IO并依赖于MyDependency.txt文件)在更改该文件时重新计算.
因此,我正在使用addDependentFile "MyDependency.txt"告诉ghc在编译代码时检查该文件是否有修改.
不幸的是,这不起作用,因为addDependentFile只相对于调用ghc的目录起作用.
我如何使用它依赖于我正在编译的文件旁边(在同一目录中)的文件?
最近,我学习了如何实现具有反引号功能的准引号,如printfQ下面的代码所示:
main = do
let itemName = "apple"
price = 1.29
[printfQ| The price of #{itemName} is #{price}. |]
Run Code Online (Sandbox Code Playgroud)
准引号的成分字符串将被传递到quoteExp printfQ :: String -> ExpQ. 所以我们要做的就是解析给定的String,找到要嵌入的名称"itemName","price"应用varE . mkName每个名称,并构建ExpQ.
现在假设我想扩展它printfQ以允许表达式嵌入,如下所示:
[printfQ| The price of #{itemNames !! i} is #{price + taxOf price}. |]
"itemNames !! i"我可以编写检测两个字符串和 的解析器"price + taxOf price"。但随后我需要一个更强版本的,这是一个将这些字符串转换为varE . mkName的函数,将它们解释为引用所使用的命名空间的表达式。String -> ExpQExpQprintfQ
我的问题:是否有任何库函数可以将此字符串转换为 AST?有一些简单的方法可以做到这一点,还是我需要编写整个 …
是否有可能将递归TH函数转换为将编译的等效形式?以下定义不起作用,因为为了编译fact,必须先编译fact.
fact :: ExpQ -> ExpQ
fact n = [|
case $n of
1 -> 1
_ -> $n * $(fact [| $n - 1 |]) |]
Run Code Online (Sandbox Code Playgroud)
这个简单的例子很容易解决(fact n = [| product [ 1.. $n] |])但是在一般情况下,如果不能将给定的函数重写为循环,是否可以定义递归TH函数?是否还有一个可行的例子?
为了澄清未来的读者:这个问题具体是关于编写递归 TH函数 - 而不是'如何拼接阶乘函数'.
我的问题的答案非常简单:
{-# LANGUAGE TemplateHaskell #-}
import Control.Monad.Fix (fix)
import Language.Haskell.TH
fact = [| \f x -> $([|
case x of
1 -> 1
_ -> f $([| x - 1 |]) * x …Run Code Online (Sandbox Code Playgroud) 对于几个项目,我需要将长字符串嵌入到Haskell源代码中.
显而易见的方法是unlines使用行列表.但是,阅读和维护这一过程非常麻烦.
cCode :: String
cCode = unlines [
"int main(int argc*, char** argv)",
" doStuff();",
"}"]
Run Code Online (Sandbox Code Playgroud)
有没有什么方法可以嵌入字符串而没有任何开销(如上面显示的列表)甚至文件?TemplateHaskell/Quasi-quotation是走这里的方式吗?
注意:此问题以问答形式回答.因此,它没有显示任何研究工作.
在Template Haskell的介绍性文本中,模板Haskell有用的一个例子是使用任意大小的元组.
任意大小的元组的目的是什么?如果数据类型相同,为什么不使用列表?如果元组中的数据类型不同,如何将其扩展为任意大小?
几乎每次我做一个记录,我发现自己后来立即添加makeLenses ''Record(从镜头),我从来没有真正使用记录给我的投影功能.事实上,看看makeLenses产生什么(使用GHC -ddump-splices标志),看起来甚至不使用那些投影功能,除了为它产生的镜头选择一个名称.
有没有办法,通过TemplateHaskell或通过预处理器,或坦率地任何其他魔法,我可以得到记录投影功能直接Van Laarhoven镜头?
要明确,这意味着
data Record a b = Record { x :: a, y :: b }
Run Code Online (Sandbox Code Playgroud)
会生成(带type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t)
x :: forall a b c. Lens (Record a b) (Record c b) a c
x f (Record _x _y) = fmap (\x' -> Record x' _y) (f …Run Code Online (Sandbox Code Playgroud) 说我有一个嵌套的结构,如下所示:
data Bar = Bar { _id :: Integer, _bars :: [Bar] }
data Foo = Foo { _bars :: [Bar] }
Run Code Online (Sandbox Code Playgroud)
我有Foo一堆Bars与各种ids 在一起:
foo = Foo [Bar 1 [Bar 2], Bar 3 [Bar 4, Bar 5]]
Run Code Online (Sandbox Code Playgroud)
怎么办,可能使用的镜头,我修改foo,从而Bar 5成为Bar 6?
我知道我曾经fclabels做过这样的事情:
mkLabel ''Foo
mkLabel ''Bar
modify bars (\bars -> ...) foo
Run Code Online (Sandbox Code Playgroud)
但是条可以无限嵌套。如何找到并修改Bar具有指定ID的?
我有一个“月”类型,大致是
\n\nnewtype Month = Month Word8\nRun Code Online (Sandbox Code Playgroud)\n\nMonth构造函数未导出的地方;相反,一个函数
mon :: Word8 -> Maybe Month\nmon i = if i > 0 && i < 13\n then Just $ Month i\n else Nothing\nRun Code Online (Sandbox Code Playgroud)\n\n被导出,仅当输入值在 1 和 12 之间(含 1 和 12)时才会返回一个值。
\n\n现在,使用Language.Haskell.TH.Quote,我定义了一个准引用 ... 运算符?...这允许我“在编译时”“创建” Month 的实例:
month :: QuasiQuoter\nmonth = QuasiQuoter { quoteDec = error "quoteDec not implemented"\n , quoteType = error "quoteType not implemented"\n , quotePat = "quotePat not implemented"\n , quoteExp = …Run Code Online (Sandbox Code Playgroud) haskell ×10
template-haskell ×10
ghc ×1
lenses ×1
list ×1
quasiquotes ×1
quotations ×1
records ×1
recursion ×1
tuples ×1