首页 文章

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

提问于
浏览
3

我有许多文件必须自动处理 . 每个文件都保存一个学生对练习的响应,该练习要求学生给出每个功能类型的某些功能的定义 .

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

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

我怎样才能做到这一点?

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

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

然后从GHCi解析返回的输出以查找student文件中的函数类型 .

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

谢谢

5 回答

  • 9

    另一种可能性是将学生的代码加载到GHCi中并使用 :browse 命令转储's exported. You can then grep for the term you'感兴趣的所有内容 . 这应该很容易实现自动化 .

    但是有一个问题: foo :: x -> xfoo :: a -> a 是相同的类型,即使文本上它们更糟糕: foo :: Int -> Intfoo :: Num x => x -> x 看起来并不相同,但是一种类型是另一种类型的实例 .

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

  • 5

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

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

    Edit based on your 2nd edit:

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

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

    • 获取模块的名称并生成一个文件 Test.hs
    module Test where
    
        import [module-name]
    
        test :: a -> b -> [(b,a)]
        test = g
    
    • run ghc -fno-code Test.hs

    • 检查输出不包含类型错误

    • 将结果写入日志文件

  • 1

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

    参见例如:

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

    也可以看看:

  • 1

    最接近的Haskell功能是 Data.Typeable.typeOf . 这是一个GHCi Session :

    > 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
    

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

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

    如果您使用它来将类型检查推迟到运行时,那么它们可以在编译时执行,例如使用 Dynamic 类似的类型,然后你肯定做错了 .

  • 1

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

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

相关问题