You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Haskell中获取函数类型?实现类似GHCi的:t命令

Getting a Function's Type as a Tuple in Haskell

Great question! You're right that Haskell's static typing means type information is erased at runtime—so you can't directly write a getTypeTuple foo that returns (Int, Int, String) as a runtime value. But there are solid workarounds using compile-time tools or GHC's built-in features to replicate what GHCi's :t command does. Let's break down your options:

1. Compile-Time Type Generation with Template Haskell

Template Haskell lets us inspect types at compile time and generate code that represents those types as values (like string tuples). Here's how to implement this for your foo function:

First, enable the Template Haskell extension and import the necessary modules:

{-# LANGUAGE TemplateHaskell #-}

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

Then write a Template Haskell function that parses a function's type and generates a tuple of type name strings:

-- Takes a function name and generates code for its type tuple
getTypeTuple :: Name -> Q Exp
getTypeTuple name = do
  -- Retrieve metadata about the function
  info <- reify name
  case info of
    VarI _ ty _ _ -> do
      -- Split the function type into arguments and return type
      let (args, result) = splitFunctionType ty
      -- Convert each type to a string expression
      argExps <- mapM typeToStringExp args
      resultExp <- typeToStringExp result
      -- Combine into a tuple expression
      return $ TupE (argExps ++ [resultExp])
    _ -> fail "getTypeTuple only works with functions"
  where
    -- Recursively split function types (e.g., Int -> Int -> String becomes [Int, Int], String)
    splitFunctionType :: Type -> ([Type], Type)
    splitFunctionType (AppT (AppT ArrowT arg) rest) =
      let (args, res) = splitFunctionType rest in (arg : args, res)
    splitFunctionType finalType = ([], finalType)

    -- Convert a type to a string literal expression
    typeToStringExp :: Type -> Q Exp
    typeToStringExp (ConT typeName) = stringE $ nameBase typeName
    typeToStringExp otherType = stringE $ show otherType

Now use it with your foo function:

foo :: Int -> Int -> String
foo a b = show a ++ show b ++ "hello"

-- Generate the type tuple at compile time
fooType :: (String, String, String)
fooType = $(getTypeTuple 'foo) -- Evaluates to ("Int", "Int", "String")

When you compile this, Template Haskell runs during the build process, inspects foo's type, and generates code that directly returns the tuple of type names.

2. Replicate GHCi's :t with the GHC API

If you want to programmatically query types like GHCi does (instead of generating code at compile time), you can use the GHC API. This lets you load modules, typecheck them, and retrieve type information.

First, add the ghc package to your dependencies. Then implement this function:

import GHC
import GHC.Paths (libdir)
import DynFlags
import OccName (mkVarOcc)
import Module (mkModuleName)

-- Get the string representation of a function's type (like :t in GHCi)
getFunctionType :: String -> String -> IO String
getFunctionType moduleName functionName = runGhc (Just libdir) $ do
  -- Initialize the GHC session
  dflags <- getSessionDynFlags
  setSessionDynFlags dflags
  -- Load the target module
  target <- guessTarget moduleName Nothing
  setTargets [target]
  load LoadAllTargets
  -- Retrieve module summary and typecheck it
  modSum <- getModSummary $ mkModuleName moduleName
  parsedMod <- parseModule modSum
  typecheckedMod <- typecheckModule parsedMod
  -- Look up the function's name
  let renamedSource = tm_renamed_source typecheckedMod
  case lookupName renamedSource (mkVarOcc functionName) of
    Just (AnId funcId) -> do
      funcType <- getType funcId
      return $ show funcType
    _ -> return "Function not found in module"

You can call this to get foo's type string:

main :: IO ()
main = do
  ty <- getFunctionType "MyModule" "foo"
  putStrLn ty -- Prints "Int -> Int -> String"

From here, you could parse this string into a tuple of type names if needed.

Key Notes

  • You can't directly return (Int, Int, String) as a runtime value because Int and String are types, not values. The closest you can get is a tuple of their string representations (as shown above).
  • All solutions rely on compile-time or tooling access to type information, since runtime type erasure means types don't exist in compiled Haskell code.

内容的提问来源于stack exchange,提问作者Kivol

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:10:17