如果使用副作用,有没有正确的方法使TH的功能安全?说,我想要一个在编译时调用git并生成版本字符串的函数:
{-# LANGUAGE TemplateHaskell #-}
module Qq where
import System.Process
import Language.Haskell.TH
version = $( [| (readProcess "git" ["rev-parse", "HEAD"] "") |] )
Run Code Online (Sandbox Code Playgroud)
版本的类型是IO String.但是版本在运行时完全没有副作用,它只在编译时有副作用.有没有办法在不使用unsafePerformIO的情况下在运行时使其纯粹?
我有一个数据类型
newtype Zq q = Zq (IntType q)
Run Code Online (Sandbox Code Playgroud)
其中'q'将是该类的一个实例
class Foo a where
type IntType a
Run Code Online (Sandbox Code Playgroud)
'IntType'只是与'q'相关的基础表示(即Int,Integral等).
我想让Zq成为Data.Vector.Unbox的一个实例.我们目前正在使用大约50行简单代码手动派生Unbox,如上面的链接所示.我们将在代码中创建几种不同类型的"Unbox",因此为每种类型写入50行并不吸引人.
我在这里找到了两个选择.一种替代方法是使用此包使用Template Haskell来派生Unbox的实例.TH代码看起来像:
derivingUnbox "Zq"
[d| instance (Foo q, U.Unbox (IntType q)) => Unbox' (ZqBasic q) (IntType q) |]
[| \ (Zq x) -> x |]
[| \ x -> Zq x |]
Run Code Online (Sandbox Code Playgroud)
问题是,我不能使用关联的类型同义词定义实例(或者我可以??)
[一个相关问题:为什么TypeSynonymInstances是FlexibleInstances所暗示的扩展,不允许关联类型的同义词实例?这在某种程度上是一个根本上不同的野兽吗?]
我目前解决这个问题的方法是将Zq重新定义为
newtype Zq q i = Zq i
Run Code Online (Sandbox Code Playgroud)
然后添加等式约束
i~(IntType q)
Run Code Online (Sandbox Code Playgroud)
在每个涉及(Zq qi)的实例中,这不是很优雅.我的(工作)Unbox派生成了
derivingUnbox …Run Code Online (Sandbox Code Playgroud) 阅读为什么引用很好,在第3节中有一个在quasiquote中拼接变量标识符的例子.
subst [:lam | $exp:e1 $exp:e2 |] x y =
let e1' = subst e1 x y
e2' = subst e2 x y
in
[:lam | $exp:e1' $exp:e2' |]
Run Code Online (Sandbox Code Playgroud)
我知道为什么递归调用subst是在外部完成的[:lam| ... |],这是因为antiVarE3.2节中的函数构建了一个TH.varE变量名.
我的问题是,除了变量名之外,还需要多少工作才能支持任意表达式拼接?
例如:
subst [:lam | $exp:e1 $exp:e2 |] x y =
[:lam | $exp:(subst e1 x y) $exp:(subst e2 x y) |]
Run Code Online (Sandbox Code Playgroud) 任何人都可以告诉为什么这段代码不能编译
data A = A {
_b :: B
}
makeLenses ''A
type B = String
Run Code Online (Sandbox Code Playgroud)
与消息
Not in scope: type constructor or class B
Run Code Online (Sandbox Code Playgroud)
这样做:
type B = String
data A = A {
_b :: B
}
makeLenses ''A
Run Code Online (Sandbox Code Playgroud)
没有makeLenses一切编译好.
为什么我不能在makeLenses之后有类型的synonim声明?
我正在尝试转移一些代码的执行,以使用GHC 8和编译时间
template-haskel-2.11。代码如下:
myThHelper :: FilePath -> Q Exp
myThHelper path =
runIO (compileThatFile path) >>= liftData
Run Code Online (Sandbox Code Playgroud)
这是该代码的简化版本,但希望可以传达我正在尝试做的事情。
注意该
liftData
函数,它是新函数,template-haskell-2.11并且承诺可以将的任何实例“提升”为表达式Data。很酷,可以编译。
但是,当我这样使用它时:
main :: IO ()
main = do
let compiled = $(myThHelper "/path/to/my/file/foo.txt")
…
Run Code Online (Sandbox Code Playgroud)
我从编译器收到以下错误消息:
• Can't find interface-file declaration for variable Data.Text.Internal.pack
Probable cause: bug in .hi-boot file, or inconsistent .hi file
Use -ddump-if-trace to get an idea of which file caused the error
• In the first argument of ‘PName’, namely
‘Data.Text.Internal.pack …Run Code Online (Sandbox Code Playgroud) 在我们的 haskell 代码库中,业务逻辑与跟踪和日志代码交织在一起。这会模糊业务逻辑,使其更难理解和调试。我正在寻找如何减少日志记录和跟踪的代码占用空间以使业务逻辑更加突出的想法。
我们的代码目前大致如下所示:
someFunction a b cs =
withTaggedSpan tracer "TRACE_someFunction" [("arg_b", show b)] $ do
logDebug logger $ "someFunction start: " <> show (trimDownC <$> cs)
result <- do ... some business logic ...
if isError result then
logError logger $ "someFunction error: " <> show result
else
logDebug logger $ "someFunction success: " <> show (trimDownResult result)
Run Code Online (Sandbox Code Playgroud)
一个观察结果是 whe 主要跟踪整个函数体并在开始和结束时记录。这应该允许将跟踪和日志记录合并到单个帮助程序中,并通过元编程自动提取函数名称和捕获值的名称。我之前在其他语言中使用过 AST 转换编译时宏和运行时内省,但没有在 Haskell 中使用过。
使用 Template Haskell、HasCallStack 或其他选项执行此操作的好方法是什么?
(交叉发布在https://www.reddit.com/r/haskell/comments/gdfu52/extracting_context_for_tracinglogging_via_haskell/)
我已经定义了很多函数(例如,100 +),每个函数都执行特定的工作但具有相同的签名.这就是:
module R001 (run) where run = <do-...>
module R002 (run) where run = <do-...>
Run Code Online (Sandbox Code Playgroud)
我想做的是提供实际的'run'作为用户输入,这样:
main = do
runWith $ read $ getLine
where
runWith :: Int -> IO ()
runWith n = R<n-padded-with-0>.run
Run Code Online (Sandbox Code Playgroud)
目前,我导入了所有合格的模块,并将所有的模块run放入一个列表中[Maybe (IO())],因此这有效:
runWith n = case Rs !! (read $ getLine) of
Just run -> run
Nothing -> undefined
Run Code Online (Sandbox Code Playgroud)
但随着n成长,我必须不断保持一个大的名单.
有没有什么办法可以使用TemplateHaskell定义大列表,或者只是在运行时根据需要加载相应的模块,而不必将每个模块分成不同的共享库.
基于epsilonhalbe的回答,我做了一些研究:
import R1 (run1)
import R2 (run2)
test = $(functionExtractor "^run")
main :: IO () …Run Code Online (Sandbox Code Playgroud) 问题
是否有可能从包含Template Haskell函数的代码生成"纯"Haskell代码?
我想得到所有Haskell模板的qutations和拼接扩展的代码?(将其提供给另一个Haskell编译器(Haste),它还不支持Template Haskell.)
例
module TupleReplicate:
tupleReplicate n = do
id <- newName "x"
return $ LamE ([VarP id]) (TupE $ replicate n $ VarE id)
Run Code Online (Sandbox Code Playgroud)
主要:
main :: IO ()
main = do
print $(tupleReplicate 3) "x"
return ()
Run Code Online (Sandbox Code Playgroud)
可以扩展到:
main :: IO ()
main = do
print (\x->(x,x,x)) "x"
return ()
Run Code Online (Sandbox Code Playgroud) 使用Template Haskell时,我收到一个关于数据类型"不在范围内"的奇怪错误.
这是我的Main.hs文件:
{-# LANGUAGE TemplateHaskell #-}
module Main where
import Control.Lens
import Data.Aeson
import Data.Aeson.TH
type Foo = Bar
data Baz = Baz
$(deriveJSON defaultOptions ''Baz)
-- $(makeLenses ''Baz)
data Bar = Bar
main :: IO ()
main = print "hello"
Run Code Online (Sandbox Code Playgroud)
在尝试编译它时,我收到以下错误:
test-0.1.0.0: configure
Configuring test-0.1.0.0...
test-0.1.0.0: build
Building test-0.1.0.0...
Preprocessing executable 'test' for test-0.1.0.0...
[1 of 1] Compiling Main ( Main.hs, .stack-work/dist/x86_64-linux/Cabal-1.22.2.0/build/test/test-tmp/Main.o )
Main.hs:9:12:
Not in scope: type constructor or class ‘Bar’
-- While building package test-0.1.0.0 using: …Run Code Online (Sandbox Code Playgroud) 在yesod书中有一段:
模板Haskell本质上是Haskell,它生成Haskell抽象语法树(AST).
TH中实际上有更多的功率,因为它实际上可以内省代码.但是,我们不在Yesod使用这些设施.
内省代码是什么意思,你可以用这个功能做什么?
haskell ×10
template-haskell ×10
compilation ×1
compile-time ×1
deriving ×1
ghc ×1
haskell-lens ×1
logging ×1
templates ×1
trace ×1