2011-07-11 21 views
10

Jadąc z C++, jestem przyzwyczajony, aby móc budować proste formy twierdzeń kompilacji, gdzie mógłbym emitują ostrzeżenia lub błędy podczas kompilacji, jeśli kilka prostych warunków (na przykład ponad prostych wyrażeń algebraicznych) nie zostały spełnione poprzez użytkowania szablon meta-programowanie i/lub cpp(1)Asercje kompilacji z GHC Haskell?

na przykład, jeśli chciałem się upewnić, mój program kompiluje się tylko wtedy, gdy Int ma przynajmniej pewną minBound/maxBound zakres lub alternatywnie, jeśli konwersja bez strat (jak w odwracalny) od Int64 do Int jest możliwe z bieżącym celem kompilacji. Czy jest to możliwe w przypadku niektórych rozszerzeń GHC Haskell? Moim pierwszym przypuszczeniem byłoby użycie TH. Czy istnieją inne obiekty GHC, które można by wykorzystać w tym celu?

+3

(Un) na szczęście nie istnieją typy zależne w Haskell, który byłby wielki do tego celu (ale które prawdopodobnie wymagają o wiele więcej można umieścić adnotacje typu). –

+0

@Alexandre: Brzmi interesująco ... Czy mógłbyś wyjaśnić, w jaki sposób można używać typów zależnych, np. Określić, czy 'Int64' zmieści się w' Int' podczas kompilacji? – hvr

+0

Typy zależne kodują pełnowymiarowy prover twierdzenia w systemie typu. Każda właściwość danych może być wyrażona w jej typie. – kamatsu

Odpowiedz

6

Oto uogólnione i nieco uproszczona wersja Anthony's example:

{-# LANGUAGE TemplateHaskell #-} 
module StaticAssert (staticAssert) where 

import Control.Monad (unless) 
import Language.Haskell.TH (report) 

staticAssert cond mesg = do 
    unless cond $ report True $ "Compile time assertion failed: " ++ mesg 
    return [] -- No need to make a dummy declaration 

Zastosowanie:

{-# LANGUAGE TemplateHaskell #-} 
import StaticAssert 

$(staticAssert False "Not enough waffles") 
+0

To jest naprawdę udoskonalenie mojego prostowania z TH! – Anthony

+0

Dziękuję wam, @hammar i @Anthony. Wymagany TH-voodoo wygląda łatwiej niż się spodziewałem: -) ... btw, dlaczego używasz składni '$ (..)'? nie jest to opcjonalne w przypadku wywołań TH najwyższego poziomu? – hvr

+0

@hvr: Tak, chociaż lubię go używać, aby ułatwić psychiczne oddzielenie TH od normalnego kodu. – hammar

5

Korzystanie TH tego nie jest tak źle. Tutaj jest modułem, który określa pożądany twierdzenie jako część szczątkowej deklaracji:

{-# LANGUAGE TemplateHaskell #-} 
module CompileTimeWarning where 
import Control.Monad (unless) 
import Data.Int (Int64) 
import Language.Haskell.TH 

assertInt = let test = fromIntegral (maxBound::Int) == (maxBound::Int64) 
      in do unless test $ report True "Int is not safe!" 
        n <- newName "assertion" 
        e <- fmap NormalB [|()|] 
        return $ [FunD n [Clause [] e []]] 

Stosując twierdzenie dotyczy deklaracja najwyższego poziomu, który nie służy do niczego innego niż twierdzenie:

{-# LANGUAGE TemplateHaskell #-} 
import CompileTimeWarning 
$(assertInt) 
Powiązane problemy