如何获取Haskell文件中任意表达式的类型?

How to get the type of an arbitrary expression in a file in Haskell?

:type 是不够的,因为我想要的表达式可能包含局部定义的变量,例如用 <-letwhere 赋值的变量。类型化的漏洞(用 _ 替换表达式并用 ghc 加载)很接近,但它们给了你那里接受的东西,这可能比你好奇的表达式更通用。

我以为我用 :type-at 找到了大奖,但我无法像我希望的那样工作。使用此文件,命名为 "thing.hs":

something :: ()
something = ()

main :: IO ()
main = return something

这是我使用 :type-at:

时得到的结果
> :set +c
> :l thing.hs
[1 of 1] Compiling Main             ( thing.hs, interpreted )
Ok, one module loaded.
Collecting type info for 1 module(s) ... 
> :type-at thing.hs 5 8 5 13 -- "return" on last line

<no location info>: error: not an expression: ‘’
> :type-at thing.hs 5 1 5 4 -- "main" on last line
 :: IO ()
> :type-at thing.hs 5 15 5 23 -- "something" on last line

<no location info>: error: not an expression: ‘’

这与使用 :type 基本相同。我希望我什至能够将 return something 的跨度传递给它并得到 Monad a => a ()IO ()。如果可以 select 在单独看到表达式的类型和表达式的类型 "at that point" 之间(在受到带有类型孔的类型的限制之后),那就更酷了,但两者都会没事。

当我尝试 :type-at thing.hs 5 8 5 14 时,我得到 :: () -> IO ():type-at thing.hs 5 14 5 24:type-at thing.hs 5 14 6 1.

一样有效

因此,右边界应该是表达式末尾后的单元格。

有时可以简单地在您感兴趣的表达式 前面使用打字洞 ,就像使用函数一样使用打洞。例如

return (f 3)
---->
return (_ (f 3))

这样,孔将被打成类似 WantedType -> OtherType 的类型,其中 WantedTypef 3 的类型。

但这并不理想,因为该漏洞会阻止类型推断完成其工作。也就是说,有时 f 3 的类型是多态的,它的上下文强制它被实例化。例如,4 + length [] 使 4 成为 Int,即使它可以是任何 Num 类型。使用 (_ 4) + length [] 在任意 Num 类型(默认为 Integer)和所需的 Int 之间引入了一个函数,使得类型推断行为异常。

另一种方法是使用翻译

return (f 3)
------>
return (f 3 `asTypeOf` _)

这应该可以更好地使用类型推断,return 正确的™ 类型。

当然,弄清楚:type-at的工作原理应该会更好。尽管如此,当您已经在现场打开了一个编辑器时,类型漏洞技巧并不会太不方便。

我相信@chi 的回答可以通过使用不实现 Show 类型类的虚拟一元类型构造函数并将其与打印函数一起使用来改进(通过避免类型推断问题):

someExpressionWeSearchType = Right $ Just (1 , ["Foo"] , getLine)

data Dummy a = Dummy a


main = do
  putStrLn "Here we go"
  --some code here...
  let exp  = someExpressionWeSearchType
  --Debug stuff => 
  print $ Dummy exp

  -- other code here 
  putStrLn "Done"

这会在加载时产生以下结果:

Prelude> :l test.hs
[1 of 1] Compiling Main             ( test.hs, interpreted )

test.hs:11:3: error:
    * No instance for (Show
                         (Dummy (Either a0 (Maybe (Bool, [[Char]], IO String)))))
        arising from a use of `print'
    * In a stmt of a 'do' block: print $ Dummy exp
      In the expression:
        do putStrLn "Here we go"
           let exp = someExpressionWeSearchType
           print $ Dummy exp
           putStrLn "Done"
      In an equation for `main':
          main
            = do putStrLn "Here we go"
                 let exp = ...
                 print $ Dummy exp
                 ....
   |
11 |   print $ Dummy exp
   |   ^^^^^^^^^^^^^^^^^
Failed, no modules loaded.

因此我们可以在 Dummy 中看到该类型:Either a0 (Maybe (Bool, [[Char]], IO String))