Haskell: получение статического типа выражения

Я ищу функцию, которая выполняет команду GHCi: type.

В идеале у него была бы подпись вроде

getStaticType :: a -> String

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

b = getStaticType zipWith
-- b = "(a -> b -> c) -> [a] -> [b] -> [c]"

(Примечание: это не имеет ничего общего с Data.Dynamic.Я просто хочу, чтобы статический тип был выведен из компилятора. Фактически для функции вообще не нужна реализация во время выполнения, так как все обращения к ней могут быть вложены как константы во время компиляции. Я предполагаю, что он существует где-то, поскольку GHCi может это сделать)

Ответ 1

Вы можете сделать это следующим образом:

import Data.Typeable

getStaticType :: Typeable a => a -> String
getStaticType = show . typeOf

Обратите внимание, что тип должен быть экземпляром Typeable. Вы можете получить Typeable автоматически, используя расширение языка DeriveDataTypeable Haskell и ... deriving (Typeable, ...).

Также обратите внимание, что полиморфные типы не могут быть идентифицированы таким образом; вы всегда должны вызывать функцию с определенным типом, поэтому вы никогда не сможете получить информацию о полиморфном типе, которую вы получаете в GHCi с компилированным кодом Haskell.

Способ GHCi заключается в том, что он использует API GHC для анализа промежуточного дерева синтаксиса 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

Затем в другом модуле (очень важно) вы можете сделать следующее:

{-# LANGUAGE TemplateHaskell #-}

import TypeOf

main = putStrLn $(getStaticType 'zipWith)

Эта программа выводит:

GHC.List.zipWith :: forall a_0 b_1 c_2 . (a_0 -> b_1 -> c_2) ->
                                         [a_0] -> [b_1] -> [c_2]

Вы можете использовать лучший симпатичный принтер, чем функцию pprint; посмотрите Language.Haskell.TH.Ppr модуль.

Ответ 2

попробуйте http://www.haskell.org/haskellwiki/GHC/As_a_library

typed targetFile targetModule = do
 defaultErrorHandler defaultFatalMessager defaultFlushOut $ do
  runGhc (Just libdir) $ do

   dflags <- getSessionDynFlags
   let dflags' = xopt_set dflags Opt_ImplicitPrelude
   setSessionDynFlags dflags'

   target <- guessTarget targetFile Nothing
   setTargets [target]
   load LoadAllTargets

   m <- getModSummary $ mkModuleName targetModule
   p <- parseModule m
   t <- typecheckModule p

   return $ typecheckedSource d