gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-05 00:02:50 25 4
gpt4 key购买 nike

我有一个玩具程序:

$ cat a.hs
main = putStrLn "Toy example"
$ runghc a.hs
Toy example

让我们添加一些 Template Haskell 到它:
$ cat b.hs
{-# LANGUAGE TemplateHaskell #-}
id [d|
main = putStrLn "Toy example"
|]
$ runghc b.hs

b.hs:3:0: parse error (possibly incorrect indentation)

那么,让我们修复缩进:
$ cat c.hs
{-# LANGUAGE TemplateHaskell #-}
id [d|
main = putStrLn "Toy example"
|]
$ runghc c.hs
Toy example

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

我可以避免缩进我的大部分模块吗? (我的真实模块不仅仅是一行代码。)(并且不使用 { ; ; } 符号?)

我确实希望在引用中捕获所有模块声明 - 在普通代码中我可以替换 (...)$ ... , 是否有 [d|...|] 的等价物那会让我避免使用右括号和缩进吗?

或者模块 A 是否可以通过某种方式说导入 A 的任何模块 B 的顶级声明都由函数 A 导出的函数自动处理?

笔记:
  • 我的真实程序中的模板 Haskell 比 id 更复杂。 — 它扫描以 prop_ 开头的变量名的声明,并构建包含它们的测试套件。有没有其他纯粹的 Haskell 方法我可以这样做,而不直接修改源文件?
  • 我正在使用 GHC v6.12.1。当我使用 GHC v7.0.3 时,针对不同位置报告 b.hs 的错误 — b.hs:3:1 - 但行为在其他方面是相同的。
  • 最佳答案

    如果测试套件用于 QuickCheck,我建议您使用新的 All模块代替:
    http://hackage.haskell.org/packages/archive/QuickCheck/2.4.1.1/doc/html/Test-QuickCheck-All.html

    它做同样的事情,只是它通过访问文件系统并解析拼接所在的文件来获取属性的名称(如果您正在使用其他一些测试框架,您仍然可以使用相同的方法)。

    如果你真的想引用整个文件,你可以使用一个 quasi-quoter 代替(它不需要缩进)。您可以轻松地在 haskell-src-meta 上构建您的报价器,但我建议不要使用这种方法,因为它不支持某些 Haskell 功能,并且可能会给出糟糕的错误消息。

    聚合测试套件是一个难题,可以扩展名称收集例程以某种方式遵循导入,但这是很多工作。这是一个解决方法:

    您可以使用 forAllProperties 的修改版本:

    import Test.QuickCheck
    import Test.QuickCheck.All
    import Language.Haskell.TH
    import Data.Char
    import Data.List
    import Control.Monad

    allProperties :: Q Exp -- :: [(String,Property)]
    allProperties = do
    Loc { loc_filename = filename } <- location
    when (filename == "<interactive>") $ error "don't run this interactively"
    ls <- runIO (fmap lines (readFile filename))
    let prefixes = map (takeWhile (\c -> isAlphaNum c || c == '_') . dropWhile (\c -> isSpace c || c == '>')) ls
    idents = nubBy (\x y -> snd x == snd y) (filter (("prop_" `isPrefixOf`) . snd) (zip [1..] prefixes))
    quickCheckOne :: (Int, String) -> Q [Exp]
    quickCheckOne (l, x) = do
    exists <- return False `recover` (reify (mkName x) >> return True)
    if exists then sequence [ [| ($(stringE $ x ++ " on " ++ filename ++ ":" ++ show l),
    property $(mono (mkName x))) |] ]
    else return []
    [|$(fmap (ListE . concat) (mapM quickCheckOne idents)) |]

    您还需要函数 runQuickCheckAll不是从 All 导出的:
    runQuickCheckAll :: [(String, Property)] -> (Property -> IO Result) -> IO Bool
    runQuickCheckAll ps qc =
    fmap and . forM ps $ \(xs, p) -> do
    putStrLn $ "=== " ++ xs ++ " ==="
    r <- qc p
    return $ case r of
    Success { } -> True
    Failure { } -> False
    NoExpectedFailure { } -> False

    在您现在定义的每个测试模块中
    propsN = $allProperties

    在哪里 N是某个数字或其他唯一标识符(或者您可以使用相同的名称并在下面的步骤中使用限定名称)。

    在您定义的主测试套件中
    props :: [(String,Property)]
    props = concat [props1, props2 ... propsN]

    如果你真的想避免为每个模块添加一个列表成员,你可以制作一个 TH 脚本来生成这个列表。

    要运行所有测试,您只需说
    runTests = runQuickCheckAll quickCheckResult props

    关于haskell - 如何避免模板 Haskell 声明引用中的额外缩进?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7619285/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com