如何内省Haskell文件以获取其定义的类型

时间:2015-10-16 09:50:56

标签: haskell

我有很多必须自动处理的文件。每个文件都保存一个学生对练习的响应,该练习要求学生为每个函数的类型给出一些函数的定义。

我的想法是创建一个加载每个学生文件的Haskell脚本,并验证每个函数是否具有预期的类型。

约束是学生文件未定义为模块。

我该怎么做?

到目前为止,我最好的替代方法是生成GHCi进程,该进程将使用GHCi命令从“测试文件”中读取stdin,例如:

:load student1.hs
:t g
... and so on ...
然后

解析GHCi返回的输出,找到学生档案中函数的类型。

是否有另一种干净的方法来加载任意Haskell文件并内省其代码?

由于

5 个答案:

答案 0 :(得分:9)

Haskell在运行时不保存类型信息。在Haskell中,类型用于静态分析阶段的运行前类型检查,并在以后擦除。您可以阅读有关Haskell类型系统here的更多信息。

您是否有理由想在运行时知道函数的类型?也许我们可以帮助解决问题:)

根据您的第二次修改进行修改:

我没有一个很好的解决方案,但这里有一个可能有用的想法:

运行每个学生模块的脚本:

  1. 获取模块的名称并生成文件chrome.runtime.onMessage.addListener(function(request, sender, sendResponse){ if(request.wordcount) { wc = request.wordcount; window.onscroll = function(){ alert('scrolled!'); } } });
  2. Test.hs
    1. 运行 module Test where import [module-name] test :: a -> b -> [(b,a)] test = g
    2. 检查输出是否包含类型错误
    3. 将结果写入日志文件

答案 1 :(得分:5)

我认为如果你有一个动态确定的.hs个文件,你需要加载,解析和内省,你可以/应该使用GHC API。

参见例如:

这些可能不是你可以直接使用的东西 - 我到目前为止自己也没有做过这样的事情 - 但是这些应该让你开始。

另见:

答案 2 :(得分:1)

最接近的Haskell功能是> import Data.Typeable > typeOf (undefined :: Int -> Char) Int -> Char > typeOf (undefined :: Int -> [Char]) Int -> [Char] > typeOf (undefined :: Int -> Maybe [Char]) Int -> Maybe [Char] > :t typeOf typeOf :: Typeable a => a -> TypeRep 。这是GHCi会议:

Typeable a

引擎盖下,typeOf约束强制Haskell保留一些类型标记直到运行时,以便TypeRep可以检索它们。通常,运行时不存在此类标记。上面的typeOf类型是此类代码的类型。

话虽如此,在Haskell中几乎从不需要这样的信息。如果您使用Dynamic来实现某些功能,那么您可能会做错了。

如果您使用它来将类型检查推迟到运行时,那么它们可以在编译时执行,例如使用Dim SafeItem, oItem Set SafeItem = CreateObject("Redemption.SafeMailItem") 'Create an instance of Redemption.SafeMailItem Set oItem = Application.CreateItem(0) 'Create a new message SafeItem.Item = oItem 'set Item property SafeItem.Recipients.Add "WOODY@WOODEN.CO.UK" SafeItem.Recipients.ResolveAll SafeItem.Subject = "Testing Redemption" SafeItem.Send 类似的类型来处理所有事情,那么你肯定做错了。

答案 3 :(得分:1)

如果该函数应该以特定名称导出,我认为最简单的方法是编写一个调用函数的测试脚本并检查它们是否返回正确的结果。如果测试脚本没有编译,则学生的提交不正确。

另一种方法是使用GHC API(有点难),或使用Template Haskell(更简单,但仍然不那么简单)。

答案 4 :(得分:1)

另一种可能性是将学生的代码加载到GHCi中,并使用:browse命令转储导出的所有内容。然后,您可以选择您感兴趣的术语。这应该很容易实现自动化。

但有一个问题:foo :: x -> xfoo :: a -> a 属于同一类型,即使文本上它们根本不匹配。您可能会考虑尝试规范化变量名称,但情况更糟:foo :: Int -> Intfoo :: Num x => x -> x看起来并不相同,但是一种类型是另一种类型的实例。

...我想这意味着我说我的答案很糟糕? : - (