打印类型签名列表

时间:2014-03-12 06:59:42

标签: haskell types

我希望能够在ghci中输入以下内容:

map showTypeSignature [(+),(-),show]

我希望ghci返回以下字符串列表:

["(+) :: Num a => a -> a -> a","(-) :: Num a => a -> a -> a","show :: Show a => a -> String"]

当然,我遇到麻烦的第一个地方是我无法构造第一个列表,因为函数的类型签名不匹配。我该怎么做才能构建这样一个列表? ghci如何完成类型签名的打印? ghci命令在哪里定义(其来源)?

3 个答案:

答案 0 :(得分:7)

你要求的东西真的不可能。您无法从Haskell中轻松确定Haskell术语的类型签名。在运行时,几乎没有可用的类型信息。由于某种原因,GHCi命令:t是GHCi命令,而不是解释的Haskell函数。

要做一些接近你想要的事情,你必须使用GHC本身作为一个库。 GHC为此目的提供GHC API。但是,您将无法使用任意Haskell术语,但必须以String表示您的术语开头。此外,在运行时调用编译器必然会产生IO输出。

答案 1 :(得分:6)

kosmikus是对的,这并没有真正奏效。并且不应该,静态类型系统是Haskell最具特色的功能之一!

但是,您可以使用Dynamic existential很好地模拟单态函数

showTypeSignature :: Dynamic -> String
showTypeSignature = show . dynTypeRep
  

Prelude Data.Dynamic> map showTypeSignature [toDyn (+), toDyn (-), toDyn (show)]
  ["整数 - >整数 - >整数","整数 - >整数 - >整数","() - > [字符]"]

正如你所看到的,ghci必须将这些函数简化为单态类型才能使其正常工作,尤其对于show来说,这显然是无用的。

答案 2 :(得分:2)

关于你为什么不能这样做的答案是非常好的,但可能还有另一种选择。如果您不关心获取Haskell列表,并且只想查看一堆内容的类型,您可以define a custom GHCi command,比如说:ts,它会显示一系列事物的类型;好的,

Prelude> :ts (+) (-) show
(+) :: Num a => a -> a -> a
(-) :: Num a => a -> a -> a
show :: Show a => a -> String

为此,我们使用:def; :def NAME EXPR,其中NAME是标识符,EXPR是类型String -> IO String的Haskell表达式,定义GHCi命令:NAME。运行:NAME ARGS计算EXPR ARGS以生成字符串,然后在GHCi中运行生成的字符串。这听起来不那么令人困惑。这就是我们的工作:

Prelude> :def ts return . unlines . map (":type " ++) . words
Prelude> :ts (+) (-) show
(+) :: Num a => a -> a -> a
(-) :: Num a => a -> a -> a
show :: Show a => a -> String

发生了什么事?这定义:ts来评估return . unlines . map (":t " ++) . words,其执行以下操作:

  • words:获取一个字符串并将其拆分为空格; 例如"(+) (-) show"变为["(+)", "(-)", "show"]
  • map (":type " ++):取自之前的每个单词并在":type "之前加上; 例如["(+)", "(-)", "show"]变为[":type (+)", ":type (-)", ":type show"]。请注意,我们现在有一个GHCi命令列表。
  • unlines:获取字符串列表并在每个字符串后面添加换行符; 例如[":type (+)", ":type (-)", ":type show"]变为":type (+)\n:type (-)\n:type show\n"。请注意,如果我们将此字符串粘贴到GHCi中,它将生成我们想要的类型签名。
  • return:将String提升为IO String,因为这是我们需要的类型。

因此,:ts name₁ name₂ ... nameₙ将连续评估:type name₁:type name₂,...,:type nameₙ并打印出结果。同样,你不能以这种方式得到一个真正的列表,但如果你只是想看看类型,这将有效。