2017-02-09 1 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에 대한 불만 사항이 있지만 글을 쓸 수 없습니다. 또 다른 방법은 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 

물론 종속성을 발생시키는 대신 관련 인스턴스를 복사 할 수도 있습니다. 그런 다음

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

DeriveLift, StandaloneDeriving, GADTsTemplateHaskellURIRef가에 (이적) 따라 모든 종류의 고아 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> 

편집

그냥 내가 당신의 질문의 마지막 부분을 대답하지 나타났습니다.

제네릭을 선호하지만 QQ API와 함께 사용하는 방법을 잘 모르겠습니다.

일반 프로그래밍에서는 컴파일 타임에 임의의 유효성 검사 코드를 실행할 수 없습니다. 이 경우 실제로는 TemplateHaskell이 필요합니다. 기껏해야 생성 된 코드 TemplateHaskell 내부에서 사용할 수는 있지만 불필요 할 것입니다.