Domanda Haskell: ottenere il tipo statico di un'espressione


Sto cercando una funzione che faccia ciò che fa il comando di tipo GHCi: type.

Idealmente, avrebbe una firma come qualcosa

getStaticType :: a -> String

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

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

(Nota: questo non ha nulla a che fare con Data.Dynamic. Voglio solo il tipo statico dedotto dal compilatore, infatti la funzione non avrebbe bisogno di un'implementazione di runtime, poiché tutte le chiamate a esso potrebbero essere inline come costanti alla compilazione tempo presumo che esista da qualche parte, dal momento che GHCi può farlo)


11
2018-05-01 15:08


origine


risposte:


Puoi farlo in questo modo:

import Data.Typeable

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

Si noti che il tipo deve essere un'istanza di Typeable. Puoi derivare Typeable automaticamente usando il DeriveDataTypeable Estensione del linguaggio Haskell e ... deriving (Typeable, ...).

Si noti inoltre che i tipi polimorfici non possono essere identificati in questo modo; devi sempre chiamare una funzione con a specifica digita, quindi non puoi mai ottenere le informazioni di tipo polimorfo che ottieni in GHCi con il codice Haskell compilato.

Il modo in cui GHCi lo fa è che utilizza l'API GHC per analizzare un albero intermedio di sintassi Haskell (AST) che contiene informazioni sul tipo. GHCi non ha lo stesso ambiente limitato che fa il tipico programma Haskell compilato; può fare un sacco di cose per scoprire più informazioni sul suo ambiente.

Con TemplateHaskell puoi farlo in questo modo; per prima cosa, crea questo modulo:

module TypeOf where

import Control.Monad

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

getStaticType :: Name -> Q Exp
getStaticType = lift <=< fmap pprint . reify

Quindi, in a modulo diverso (molto importante), puoi fare quanto segue:

{-# LANGUAGE TemplateHaskell #-}

import TypeOf

main = putStrLn $(getStaticType 'zipWith)

Questo programma emette:

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

Puoi usare una stampante carina migliore di pprint funzione; dai un'occhiata al Language.Haskell.TH.Ppr modulo.


20
2018-05-01 15:11



provare 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

1
2017-09-19 17:41