Haskell:获取表达式的静态类型

drw*_*owe 11 haskell types ghc

我正在寻找一个能够执行GHCi:type命令的功能.

理想情况下,它会有类似的签名

getStaticType :: a -> String

a = getStaticType (1+2)
-- a = "(Num t) => t"

b = getStaticType zipWith
-- b = "(a -> b -> c) -> [a] -> [b] -> [c]"
Run Code Online (Sandbox Code Playgroud)

(注意:这与Data.Dynamic无关.我只想从编译器推断出静态类型.实际上该函数根本不需要运行时实现,因为对它的所有调用都可以在编译时作为常量内联时间.我假设它存在于某处,因为GHCi可以做到这一点)

dfl*_*str 20

你可以这样做:

import Data.Typeable

getStaticType :: Typeable a => a -> String
getStaticType = show . typeOf
Run Code Online (Sandbox Code Playgroud)

请注意,类型必须是.的实例Typeable.您可以Typeable使用DeriveDataTypeableHaskell语言扩展和自动派生... deriving (Typeable, ...).

另请注意,无法以这种方式识别多态类型; 您必须始终调用具有特定类型的函数,因此您永远无法获得使用已编译的Haskell代码在GHCi中获得的多态类型信息.

GHCi的工作方式是它使用GHC API来分析包含类型信息的中间Haskell抽象语法树(AST).GHCi没有与典型编译的Haskell程序相同的受限环境; 它可以做很多事情来找到有关其环境的更多信息.

使用TemplateHaskell,您可以这样做; 首先,创建此模块:

module TypeOf where

import Control.Monad

import Language.Haskell.TH
import Language.Haskell.TH.Syntax

getStaticType :: Name -> Q Exp
getStaticType = lift <=< fmap pprint . reify
Run Code Online (Sandbox Code Playgroud)

然后,在另一个模块(非常重要)中,您可以执行以下操作:

{-# LANGUAGE TemplateHaskell #-}

import TypeOf

main = putStrLn $(getStaticType 'zipWith)
Run Code Online (Sandbox Code Playgroud)

该计划输出:

GHC.List.zipWith :: forall a_0 b_1 c_2 . (a_0 -> b_1 -> c_2) ->
                                         [a_0] -> [b_1] -> [c_2]
Run Code Online (Sandbox Code Playgroud)

您可以使用比pprint功能更好的漂亮打印机; 看看Language.Haskell.TH.Ppr模块.

  • TBH,Haskell非常强烈的"反魔法". (5认同)