如何获取Haskell文件中任意表达式的类型?
How to get the type of an arbitrary expression in a file in Haskell?
:type
是不够的,因为我想要的表达式可能包含局部定义的变量,例如用 <-
、let
或 where
赋值的变量。类型化的漏洞(用 _
替换表达式并用 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
的类型,其中 WantedType
是 f 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))
:type
是不够的,因为我想要的表达式可能包含局部定义的变量,例如用 <-
、let
或 where
赋值的变量。类型化的漏洞(用 _
替换表达式并用 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
的类型,其中 WantedType
是 f 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))