【问题标题】:printing a list of type signatures打印类型签名列表
【发布时间】:2014-03-14 15:05:00
【问题描述】:

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

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

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

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

当然,我遇到的第一个问题是我无法构造第一个列表,因为函数的类型签名不匹配。我能做些什么来构建这样一个列表? ghci如何完成类型签名的打印? ghci 命令 :t 定义在哪里(它的来源)?

【问题讨论】:

    标签: haskell types


    【解决方案1】:

    您所要求的实际上是不可能的。您无法从 Haskell 中轻松确定 Haskell 术语的类型签名。在运行时,几乎没有可用的类型信息。 GHCi 命令:t 是一个 GHCi 命令,而不是解释的 Haskell 函数,这是有原因的。

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

    【讨论】:

      【解决方案2】:

      kosmikus 是对的,这并没有真正奏效。 不应该,静态类型系统是 Haskell 最显着的特征之一!

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

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

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

      如您所见,ghci 必须在这里将函数归结为单态类型才能正常工作,尤其是对于 show,这显然是无用的。

      【讨论】:

        【解决方案3】:

        您为什么不能这样做的答案非常好,但可能还有另一种选择。如果您不关心获取 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ₙ 并打印出结果。同样,您无法通过这种方式获得真正的列表,但如果您只想查看类型,这将起作用。

        【讨论】:

          猜你喜欢
          • 2016-05-03
          • 2022-01-14
          • 2015-08-30
          • 2019-10-27
          • 2013-02-01
          • 1970-01-01
          • 2023-03-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多