编译时检查的URI

时间:2017-02-09 00:41:14

标签: haskell types ghc template-haskell

我想创建一个表达式,以便我有一个编译时错误或URI

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

应编译,但

[uri|foo:/bar:\|]

不应该。

我遇到过QuasiQuotes,显然是出于这种问题。但是,我似乎无法从解析后的Q Exp创建URI

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 |]
                  }

无法编译,因为它需要Lift的{​​{1}}实例。但是,由于GADT的性质,我不确定如何创建一个。

URI

抱怨没有deriving instance Lift (URIRef a) ,但我不知道写一个。另一种方式是Lift ByteString,但是

失败了
Data URI

我更喜欢使用 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) ,但我不确定如何将它们与QQ API一起使用。

1 个答案:

答案 0 :(得分:10)

您几乎就在那里 - 您正在寻找的Lift Bytestring个实例已在th-lift-instances包中提供。

import Instances.TH.Lift

当然,您也可以复制相关实例,而不是产生依赖。

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

然后,在启用DeriveLiftStandaloneDerivingGADTsTemplateHaskell的情况下,您可以为所有类型创建孤立Lift个实例{{1依赖(传递)on。

URIRef

通过此添加,您的代码现在可以编译。在GHCi,我得到以下互动,确认一切正常。

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

修改

刚刚注意到我从未回答你问题的最后部分。

  

我更喜欢使用Generics,但我不确定如何将它们与QQ API一起使用。

这是不可能的 - 通用编程不允许您在编译时执行任意验证代码。你真的需要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> 。充其量你可以在生成的TemplateHaskell代码中使用它们,但这是不必要的(那里没有通用的东西)。