Parsing 在编译前向Haskell函数添加额外参数
作为动态加载用户输入字符串作为Haskell源代码的程序的一部分,我想在编译用户输入之前对其进行一些预处理 我希望能够做的一件事是搜索源代码中的特定函数实例,并为它们添加一个额外的参数。例如,我可能希望出现以下所有情况:Parsing 在编译前向Haskell函数添加额外参数,parsing,haskell,preprocessor,metaprogramming,Parsing,Haskell,Preprocessor,Metaprogramming,作为动态加载用户输入字符串作为Haskell源代码的程序的一部分,我想在编译用户输入之前对其进行一些预处理 我希望能够做的一件事是搜索源代码中的特定函数实例,并为它们添加一个额外的参数。例如,我可能希望出现以下所有情况: addThreeNumbers 3 5 成为: addThreeNumbers 3 5 10 实现这种行为的最佳方式是什么?在GHCAPI/模板Haskell中使用函数操作某种抽象语法树是否足够复杂?或者这是一件简单的事情,可以通过某种Haskell预处理/解析库来完成吗?
addThreeNumbers 3 5
成为:
addThreeNumbers 3 5 10
实现这种行为的最佳方式是什么?在GHCAPI/模板Haskell中使用函数操作某种抽象语法树是否足够复杂?或者这是一件简单的事情,可以通过某种Haskell预处理/解析库来完成吗?如果是这样,您会推荐哪些库和资源?Ghc 7.6、Ghc pkg hide和Ghc的-package选项允许您在导入文件和导入文件之间无缝添加一层
例如:
使用您自己的Data.Char、standard.cabal文件和cabal安装创建一个包
{-# language PackageImports #-}
module Data.Char (
toUpper
, Char
, String
-- ... Export every else from "Base" Data char because the limitation of
-- the current export facility you can not use
-- module Data.Char hiding (toUpper)
) where
import "base" Data.Char hiding (toUpper)
import qualified "base" Data.Char as OldChar
toUpper :: Char -> IO Char
toUpper c = do
print "Oh Yeahhhhhhhhh"
return $ OldChar.toUpper c
隐藏基本包ghc pkg Hide base
——这会隐藏许多模块,在这种情况下,如果需要,您需要包装所有模块
> ghci -XNoImplicitPrelude -- We need language flag because the Prelude is in
-- base and I did not make a wrapped Prelude
ghci> import Data.Char
ghci> toUpper 'c' -- The wrapped function
"Oh Yeahhhhhhhhh"
'C'
ghci> isSpace ' ' -- The unwrapped normal Data.Char function
True
现在,您可以使用TemplateHaskell包装您的函数,并调用您需要的任何IO操作来获取外部信息。用户甚至不需要更改任何函数调用或模块导入,只需在名称中添加“internal”即可
能够无缝地包装模块接口还意味着您可以更改导入模块的植入,而无需接触包/模块代码或您正在使用的现有代码库;你只需要做一个中间层
编辑对问题的答复:
当然可以,ghc api可以让您完成所有这一切,但它要复杂得多,我希望的例子更少,我似乎看到更多的人在使用它时遇到困难,然后是成功的故事
- 用于代码的评估
- 建议对模块进行动态加载
- haskell src ext建议解析和更改代码。这是用来对代码进行小修改的,是您最好的选择。据报道,它涵盖了Haskell 2010的大部分(全部?),以及许多但不是全部GHC扩展,如果您不喜欢我提供的第一个解决方案,它可能是您的最佳选择
{-# language PackageImports #-}
module Data.Char (
toUpper
, Char
, String
-- ... Export every else from "Base" Data char because the limitation of
-- the current export facility you can not use
-- module Data.Char hiding (toUpper)
) where
import "base" Data.Char hiding (toUpper)
import qualified "base" Data.Char as OldChar
toUpper :: Char -> IO Char
toUpper c = do
print "Oh Yeahhhhhhhhh"
return $ OldChar.toUpper c
隐藏基本包ghc pkg Hide base
——这会隐藏许多模块,在这种情况下,如果需要,您需要包装所有模块
> ghci -XNoImplicitPrelude -- We need language flag because the Prelude is in
-- base and I did not make a wrapped Prelude
ghci> import Data.Char
ghci> toUpper 'c' -- The wrapped function
"Oh Yeahhhhhhhhh"
'C'
ghci> isSpace ' ' -- The unwrapped normal Data.Char function
True
现在,您可以使用TemplateHaskell包装您的函数,并调用您需要的任何IO操作来获取外部信息。用户甚至不需要更改任何函数调用或模块导入,只需在名称中添加“internal”即可
能够无缝地包装模块接口还意味着您可以更改导入模块的植入,而无需接触包/模块代码或您正在使用的现有代码库;你只需要做一个中间层
编辑对问题的答复:
当然可以,ghc api可以让您完成所有这一切,但它要复杂得多,我希望的例子更少,我似乎看到更多的人在使用它时遇到困难,然后是成功的故事
- 用于代码的评估
- 建议对模块进行动态加载
- haskell src ext建议解析和更改代码。这是用来对代码进行小修改的,是您最好的选择。据报道,它涵盖了Haskell 2010的大部分(全部?),以及许多但不是全部GHC扩展,如果您不喜欢我提供的第一个解决方案,它可能是您的最佳选择
据我所知,GHC-API是唯一一个与GHC兼容的代码完全兼容的API,但它要复杂得多,文档较少,并且更可能从GHC版本更改为GHC版本,或者从我有限的经验来看,至少没有承诺它会是相同的。我建议把一个模块放在中间,因为它看起来是最快的,可以用很好的测试覆盖率,用最少的新知识,满足我从你的问题中挑选出来的要求。这取决于什么?类型?名字?只是给你一个最简单的开始讨论的方法。。。将代码的
addThreeNumbers
重命名为addThreeNumbersInternal
并定义addThreeNumbers x y=addThreeNumbersInternal x y 10
?@这完全取决于此时的名称。例如,我想说“查找所有出现的'AddThreeNumber'函数,并为它们添加一个值为10的额外参数”@Daniel Wagner这似乎确实适用于简单的情况,但我想象的情况是:1。我可能需要根据用户输入代码之外的信息(例如,外部操作的时间戳,或函数出现的行号)添加参数值2。这很容易改变。比如说,明天我决定给addThreeNumber的所有出现添加两个参数