标签: template-haskell

使用模板haskell包装带有源信息的函数(例如行号)的正确方法是什么

假设我从一个函数开始

fromJust Nothing = error "fromJust got Nothing!"
fromJust (Just x) = x
Run Code Online (Sandbox Code Playgroud)

然后,我想通过Template Haskell添加源信息以获得更好的错误消息.让我们想象一下,我可以在函数中添加一个额外的参数

fromJust' loc Nothing = error $ "fromJust got Nothing at " ++ (loc_filename loc)
fromJust' loc (Just x) = x
Run Code Online (Sandbox Code Playgroud)

然后有一些fromJust我可以在源代码中使用的宏,比如

x = $fromJust $ Map.lookup k m
Run Code Online (Sandbox Code Playgroud)

我确实设法通过使用quasiquotes并提取源文件名的字符串来破解它.似乎Loc没有Lift实例.有没有更好的办法?

fromJustErr' l (Nothing) =
    error $ printf "[internal] fromJust error\
        \\n    (in file %s)" l
fromJustErr' l (Just x) = x
fromJustErr = do
    l <- location
    let fn = loc_filename …
Run Code Online (Sandbox Code Playgroud)

haskell template-haskell

5
推荐指数
1
解决办法
523
查看次数

如何避免模板 Haskell 声明引用中的额外缩进?

我有一个玩具程序:

$ cat a.hs
main = putStrLn "Toy example"
$ runghc a.hs
Toy example
Run Code Online (Sandbox Code Playgroud)

让我们向其中添加一些模板 Haskell:

$ cat b.hs
{-# LANGUAGE TemplateHaskell #-}
id [d|
main = putStrLn "Toy example"
|]
$ runghc b.hs

b.hs:3:0: parse error (possibly incorrect indentation)
Run Code Online (Sandbox Code Playgroud)

那么,让我们修复缩进:

$ cat c.hs
{-# LANGUAGE TemplateHaskell #-}
id [d|
 main = putStrLn "Toy example"
 |]
$ runghc c.hs
Toy example
Run Code Online (Sandbox Code Playgroud)

一个空格就足够了,但我必须缩进两个尾随行。

我可以避免缩进我的大部分模块吗?(我的 Real Modules 不止一行代码。)(而且没有使用{ ; ; }符号?)

我确实希望在引用中捕获所有模块声明 - 在正常代码中我可以替换(...)$ ... …

haskell template-haskell

5
推荐指数
1
解决办法
323
查看次数

从名称创建数据类型?

可能重复:
Template Haskell声明中的局部变量

我正在尝试构造一个简单的模板Haskell函数,给定一个像"Foo"这样的字符串,将构造语法树data Foo = Foo.

现在,我正在尝试做类似的事情mkDecl name = [d|data $(conT name) = Foo|],但是这给了我错误:"格式错误的类型或类声明:$(conT name)".知道发生了什么事吗?

我可以用dataD等写出来,但我更喜欢这种方式,因为它会更清楚地发生了什么.

haskell template-haskell

5
推荐指数
0
解决办法
118
查看次数

Template Haskell可以生成多参数类型类实例吗?

最新的(2.8.0.0)定义Dec具有以下实例构造函数:

InstanceD Cxt Type [Dec]
Run Code Online (Sandbox Code Playgroud)

似乎只能实例化一种类型.有办法解决这个问题吗?

haskell template-haskell

5
推荐指数
2
解决办法
304
查看次数

使用TemplateHaskell中的列表

这是我正在使用的教程.

他有一个例子,tupleReplicate它返回一个带值的函数并复制它:

tupleReplicate :: Int -> Q Exp
tupleReplicate n = do id <- newName "x"
                      return $ LamE (VarP id)
                                    (TupE $ replicate n $ VarE id)
Run Code Online (Sandbox Code Playgroud)

那么VarE id返回一个表达式,然后可以使用replicate?我的问题是,如果id是列表,这将如何工作?我想做的事情如下:

let vals = mkName "vals"
LamE (ListP vals) (map reverse $ ListE vals)
Run Code Online (Sandbox Code Playgroud)

除非因为ListE退货Exp而不起作用[Exp].

更一般地说,我想在TemplateHaskell中编写一个获取列表并将函数应用于它的函数.


这里也有一些示例代码在这里,我试图写这样一个函数

makeModel (id_ : name_ : []) = Person (fromSql id_) (fromSql name_)
Run Code Online (Sandbox Code Playgroud)

haskell template-haskell

5
推荐指数
1
解决办法
172
查看次数

无法与'#'匹配`*'

到底发生了什么:

"Couldn't match kind `*' against `#'"
Run Code Online (Sandbox Code Playgroud)

我在使用TemplateHaskell(ghci -XTemplateHaskell)的GHCi中尝试以下内容

$(reify ''Show >>= dataToExpQ (const Nothing))
Run Code Online (Sandbox Code Playgroud)

我希望得到一个Exp(这有一个Show的实例).我这样做是为了在应用程序中插入有关haskell类型的信息,使其可用作实际数据,而不是字符串.

我的目标是:

info :: Info
info = $(reify ''Show >>= dataToExpQ (const Nothing))
Run Code Online (Sandbox Code Playgroud)

我真的不明白这个错误信息,反正是什么'#'?如果有#,是否有也# -> #还是* -> #?它是否与类型相关的类型有关(虽然我不知道那可能是什么)?


好的,所以我现在明白GHC有各种各样的层次结构,而'#'是一种特殊的未装箱类型.一切都很好,但为什么会弹出这个错误?也许未装箱的类型与genercis不相称?

我还不完全确定这对我有意义,因为我认为未装箱的类型是由编译器执行的优化.我还认为,如果存在数据实例,则需要存在可能包含在数据结构中的所有类型.

经过进一步调查,我认为Names存在问题,有没有办法在dataToExpQ中规避它们?怎么用这个论点呢?

haskell generic-programming ghc template-haskell type-kinds

5
推荐指数
1
解决办法
341
查看次数

函数作为模板haskell引用中使用的参数

这部分是一个函数的Lift实例的后续操作.但是,答案是全局定义函数或在引号内重写它.但是,我们将在fooa f的范围内使用很多具有不同功能的let.这使得我们几乎不可能定义f的多个全局版本.后者在引用中编写函数的解决方案似乎等同于在函数上编写一个提升.

那么,有没有办法解除在Haskell模板引用中使用的函数作为参数?


一个非常人为的例子:

foo.hs

{-# Language TemplateHaskell #-}
import Language.Haskell.TH

foo :: (Int->Int) -> Int -> ExpQ
foo f x = [|f x|]

g :: ExpQ
g = 
    let 
        f = (\x -> x+1)
        f' = (\x' -> f(x') + 1)
    in foo f' 0
Run Code Online (Sandbox Code Playgroud)

将失败:

foo.hs:5:11:
    No instance for (Language.Haskell.TH.Syntax.Lift (Int -> Int))
      arising from a use of ‘Language.Haskell.TH.Syntax.lift’
    In the expression: Language.Haskell.TH.Syntax.lift f
    In the expression: …
Run Code Online (Sandbox Code Playgroud)

haskell template-haskell

5
推荐指数
1
解决办法
538
查看次数

HTF不测试TH生成的道具

我想在我的库中对各种类型进行一些类似的测试.

为简化起见,假设我有许多实现Num类的向量类型,并且我想生成相同的QuickCheck属性检查prop_absNorm x y = abs x + abs y >= abs (x+y),该检查可以对库中的所有类型起作用.

我使用TH生成这样的属性:

$(writeTests
    (\t ->
        [d| prop_absNorm :: $(t) -> $(t) -> Bool
            prop_absNorm x y = abs x + abs y >= abs (x+y)
        |])
 )
Run Code Online (Sandbox Code Playgroud)

我生成测试的函数具有以下签名:

writeTests :: (TypeQ -> Q [Dec]) -> Q [Dec]
Run Code Online (Sandbox Code Playgroud)

此函数查找我的矢量类的所有实例VectorMath (n::Nat) t(以及同时的实例Num)reify ''VectorMath并相应地生成所有prop函数. -ddump-splices显示这样的事情:

prop_absNormIntX4 :: Vector 4 Int -> Vector 4 Int -> Bool
prop_absNormIntX4 x y = …
Run Code Online (Sandbox Code Playgroud)

haskell quickcheck template-haskell htf

5
推荐指数
1
解决办法
135
查看次数

使用 Esqueleto 和 Template Haskell 动态构建 SQL 查询?

我正在用 Yesod 和 Persistent 编写一个 webapp。我有一个包含多个表的 SQL 数据库,其中包含我的“项目”的特征。我有一个主表和带有多个值的 Option 与 id 链接的额外表。

用户应该能够选择他想要过滤的那些特征并指定过滤器值。如果用户筛选操作系统,则 SQL 查询的许可证和编码将如下所示:

runquery :: (YesodPersist site, YesodPersistBackend site ~ SqlBackend) =>
             String -> String -> String
            -> HandlerT site IO [Entity Project]
runquery os license coding = runDB
  $ select $ distinct
  $ from $ \(p `InnerJoin` pl `InnerJoin` l `InnerJoin` pc
            `InnerJoin` c `InnerJoin` o `InnerJoin` po) -> do
     on $ p ^. ProjectId ==. pl ^. ProjectLicenseFkProjectId
     on $ p ^. ProjectId ==. pc ^. …
Run Code Online (Sandbox Code Playgroud)

haskell template-haskell esqueleto haskell-persistent

5
推荐指数
1
解决办法
227
查看次数

围模板功能找不到Libz.so

<command line>: can't load .so/.DLL for: libz.so (libz.so: cannot open shared object file: no such file or directory)

这是我在尝试安装某些WAI库时遇到的错误:

  • 围应用静电-3.1.6.2
  • 围的WebSockets-3.0.1.2

这似乎与模板Haskell有动态链接问题有关.链接到zlib(或libz或z或libz1g或其他任何月份包管理器选择调用标准压缩库的味道)的其他包工作正常,只有那些试图在编译时动态链接到它的包时间.

我用过 nix-env -i zlib && nix-shell -p zlib

我做apt-get installzlib1g,zlib1g-dev,lib32z1,zlib1g:i386,的libc6-I386, ,lib32stdc++6,lib32gcc1(?!)lib32ncurses5其他zlib的问题的建议.

whereis libz.so给人/usr/lib/x86_64-linux-gnu/libz.a /usr/lib/x86_64-linux-gnu/libz.so所以我觉得库实际安装.

我通过剥离所有的TH代码得到了一个精简版的wai-app-static工作,但我无法在不打破整个包的情况下从wai-websockets中提取它.

有没有人找到一种方法来安装这些库,最好是使用Nix,但是在这一点上我可以实现它.我已经尝试了三天来获得一个有效的构建,并且已经耗费了整个星期的项目时间,而没有编写我自己的代码.我会采取任何可行的黑客攻击.


有人要求使用命令行.这是由cabal生成的:

/home/jfmiller28/.nix-profile/bin/ghc --make -fbuilding-cabal-package -O -static -dynamic-too -dynosuf dyn_o -dynhisuf dyn_hi -outputdir dist/build -odir dist/build -hidir dist/build -stubdir dist/build -i -idist/build …
Run Code Online (Sandbox Code Playgroud)

haskell zlib yesod template-haskell haskell-wai

5
推荐指数
1
解决办法
310
查看次数