2012-05-01 14 views
11

GHCi: type komutunun yaptığı bir işlevi arıyorum.Haskell: bir ifadenin statik türünü almak

İdeal olarak, bu

getStaticType :: a -> String 

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

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

(Not gibi bir imza bir şey olurdu.:. Bu Data.Dynamic ile sadece derleyici anlaşılmaktadır statik tip istiyorum ilgisi yoktur Aslında fonksiyon wouldn' buna tüm çağrılar derleme zamanında sabitleri olarak satır içine yerleştirilmiş olabilir gibi t hiç bir çalışma zamanı uygulaması gerek GHCi)

cevap

20

bunu yapabilir beri böyle yapabilirsin, bir yere var tahmin ediyorum.

import Data.Typeable 

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

Türün Typeable örneğinin olması gerektiğini unutmayın. Typeable otomatik olarak DeriveDataTypeable Haskell dil uzantısını ve ... deriving (Typeable, ...)'u kullanarak türetebilirsiniz. Ayrıca, polimorfik türlerin bu şekilde tanımlanamayacağını unutmayın; Her zaman bir özel türüyle bir işlevi çağırmanız gerekir, bu yüzden derlenmiş Haskell koduyla GHCi'ye aldığınız polimorfik türden bilgiyi asla alamazsınız.

GHCi'nin yaptığı gibi, tip bilgisi içeren bir Haskell özet sözdizimi ağacını (AST) analiz etmek için GHC API'sini kullanmasıdır. GHCi, tipik derlenmiş Haskell programınızın yaptığı aynı kısıtlanmış ortama sahip değildir; Çevresi hakkında daha fazla bilgi edinmek için birçok şey yapabilir.

TemplateHaskell ile bunu yapabilirsiniz;

{-# LANGUAGE TemplateHaskell #-} 

import TypeOf 

main = putStrLn $(getStaticType 'zipWith) 

Bu program çıktıları:

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

bir farklı modül (çok önemli) içinde, aşağıdakileri yapabilirsiniz, Sonra

module TypeOf where 

import Control.Monad 

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

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

: birincisi, bu modül oluşturmak pprint işlevinden daha iyi bir yazıcı kullanabilirsiniz; Language.Haskell.TH.Ppr modülüne bir göz atın.

+0

kullanım kendinden belgeleyen kodu ve günlük içindir deneyin. Bu çok da kötü bir şey değil, zaten tüm bilgilere sahip olan derleyicide bir "sihirli işlev" olarak uygulanması önemsiz gibi gözüküyor. – drwowe

+5

TBH, Haskell oldukça güçlü bir "anti-sihir". –

+0

@drwowe doğrudur - böyle bir derleyici içinde uygulamak oldukça kolay olurdu. Bu, C. – Ingo

1

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