2017-02-09 10 views
6

私はコンパイル時のエラーやURIというような表現をしたいと思います。コンパイル時にチェックされたURI

[uri|http://stackoverflow.com|] 

はコンパイルする必要がありますが、

[uri|foo:/bar:\|] 

はいけません。

私はQuasiQuotesに出くわしました。これは明らかにこの種の問題です。しかし、私はURIからQ Expを作成することはできません。それはURIためLiftインスタンスを望んでいるので

import Language.Haskell.TH.Quote 
import Language.Haskell.TH.Syntax 
import Language.Haskell.TH 
import URI.ByteString 
import Data.ByteString.Char8 


uri = QuasiQuoter { quoteExp = \s -> 
         let 
         uri = either (\err -> error $ show err) id (parseURI laxURIParserOptions (pack s)) 
         in 
         [| uri |] 
        } 

は、コンパイルされません。しかし、私はGADTの性質のため、どのように作成するのかは分かりません。

deriving instance Lift (URIRef a) 

Lift ByteStringについてはお詫びしますが、私は1つ書くことはできません。もう一つの方法は、Data URIだろうが、それは私がGenericsを使用することを好むだろうが、私はQQ APIとそれらを使用するかどうかはわかりません

85 1 error   • Couldn't match type ‘a’ with ‘Absolute’ 
    ‘a’ is a rigid type variable bound by 
    the instance declaration at uri-bytestring/src/URI/ByteString/Types.hs:85:1 
    Expected type: c (URIRef a) 
    Actual type: c (URIRef Absolute) 
• In the expression: k (k (k (k (k (z URI))))) 
    In a case alternative: 
     ghc-prim-0.5.0.0:GHC.Types.I# 1# -> k (k (k (k (k (z URI))))) 
    In the expression: 
    case constrIndex c of { 
     ghc-prim-0.5.0.0:GHC.Types.I# 1# -> k (k (k (k (k (z URI))))) 
     _ -> k (k (k (k (z RelativeRef)))) } 
    When typechecking the code for ‘gunfold’ 
    in a derived instance for ‘Data (URIRef a)’: 
    To see the code I am typechecking, use -ddump-deriv 
• Relevant bindings include 
    gunfold :: (forall b r. Data b => c (b -> r) -> c r) 
       -> (forall r. r -> c r) -> Constr -> c (URIRef a) 
     (bound at uri-bytestring/src/URI/ByteString/Types.hs:85:1) (haskell-stack-ghc) 

で失敗します。

答えて

10

あなたが探しているLift Bytestringインスタンスは、th-lift-instancesパッケージで提供されています。

import Instances.TH.Lift 

もちろん、依存関係を引き起こさずに、関連するインスタンスをコピーすることもできます。 DeriveLiftStandaloneDerivingGADTs、およびTemplateHaskell

その後
-- ByteString 
instance Lift ByteString where 
    lift b = [| pack $(lift $ unpack b) |] 

は、あなたが上(推移)依存URIRefすべてのタイプのために孤児Liftインスタンスを作成することができ、オン。

deriving instance Lift (URIRef a) 
deriving instance Lift Authority 
deriving instance Lift UserInfo 
deriving instance Lift Query 
deriving instance Lift Host 
deriving instance Lift Port 
deriving instance Lift Scheme 

これで、コードがコンパイルされるようになりました。 GHCiで私は次のようなやり取りをして、すべてが機能していることを確認します。

ghci> :set -XQuasiQuotes 
ghci> [uri|http://stackoverflow.com|] 
URI {uriScheme = Scheme {schemeBS = "http"}, uriAuthority = Just (Authority {authorityUserInfo = Nothing, authorityHost = Host {hostBS = "stackoverflow.com"}, authorityPort = Nothing}), uriPath = "", uriQuery = Query {queryPairs = []}, uriFragment = Nothing} 
ghci> [uri|foo:/bar:\|] 

<interactive>:3:1: error: 
    • Exception when trying to run compile-time code: 
     MalformedPath 
CallStack (from HasCallStack): 
    error, called at uri.hs:25:47 in main:Main 
     Code: quoteExp uri "foo:/bar:\\" 
    • In the quasi-quotation: [uri|foo:/bar:\|] 
ghci> 

EDIT

ちょうど私があなたの質問の最後の部分に答えはありません気づきました。

私はジェネリックスを使用することをお勧めしますが、私はQQ APIでそれらを使用する方法がわかりません。

一般的なプログラミングでは、コンパイル時に任意の検証コードを実行することはできません。これには実際にTemplateHaskellが必要です。最高でも、TemplateHaskellコードの内部でそれらを使用することはできますが、それは不要です(そこには一般的なことはありません)。

関連する問題