编译时检查的 URI
Compile-time checked URIs
我想创建一个表达式,使我有编译时错误或 URI。
[uri|http://whosebug.com|]
应该编译,但是
[uri|foo:/bar:\|]
不应该。
我遇到过QuasiQuotes,显然是针对此类问题的。但是,我似乎无法从解析的 URI
.
创建 Q Exp
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 |]
}
不编译,因为它需要 URI
的 Lift
实例。但是,由于 GADT 的性质,我不确定如何创建一个。
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)
我更愿意使用 Generics
,但我不确定如何将它们与 QQ API 一起使用。
您就快完成了 - th-lift-instances
包中提供了您正在寻找的 Lift Bytestring
实例。
import Instances.TH.Lift
当然,你也可以只复制相关实例而不产生依赖。
-- ByteString
instance Lift ByteString where
lift b = [| pack $(lift $ unpack b) |]
然后,在 DeriveLift
、StandaloneDeriving
、GADTs
和 TemplateHaskell
开启的情况下,您可以为所有类型创建孤立的 Lift
实例 URIRef
取决于(传递地)。
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://whosebug.com|]
URI {uriScheme = Scheme {schemeBS = "http"}, uriAuthority = Just (Authority {authorityUserInfo = Nothing, authorityHost = Host {hostBS = "whosebug.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>
编辑
刚注意到我没有回答你问题的最后一部分。
I'd prefer to use Generics, but I'm not sure how to use them with the QQ APIs.
那是不可能的 - 泛型编程不允许您在编译时执行任意验证代码。为此,您确实需要 TemplateHaskell
。充其量你可以在生成的 TemplateHaskell
代码中使用它们,但这是不必要的(那里没有通用的东西)。
我想创建一个表达式,使我有编译时错误或 URI。
[uri|http://whosebug.com|]
应该编译,但是
[uri|foo:/bar:\|]
不应该。
我遇到过QuasiQuotes,显然是针对此类问题的。但是,我似乎无法从解析的 URI
.
Q Exp
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 |]
}
不编译,因为它需要 URI
的 Lift
实例。但是,由于 GADT 的性质,我不确定如何创建一个。
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)
我更愿意使用 Generics
,但我不确定如何将它们与 QQ API 一起使用。
您就快完成了 - th-lift-instances
包中提供了您正在寻找的 Lift Bytestring
实例。
import Instances.TH.Lift
当然,你也可以只复制相关实例而不产生依赖。
-- ByteString
instance Lift ByteString where
lift b = [| pack $(lift $ unpack b) |]
然后,在 DeriveLift
、StandaloneDeriving
、GADTs
和 TemplateHaskell
开启的情况下,您可以为所有类型创建孤立的 Lift
实例 URIRef
取决于(传递地)。
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://whosebug.com|]
URI {uriScheme = Scheme {schemeBS = "http"}, uriAuthority = Just (Authority {authorityUserInfo = Nothing, authorityHost = Host {hostBS = "whosebug.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>
编辑
刚注意到我没有回答你问题的最后一部分。
I'd prefer to use Generics, but I'm not sure how to use them with the QQ APIs.
那是不可能的 - 泛型编程不允许您在编译时执行任意验证代码。为此,您确实需要 TemplateHaskell
。充其量你可以在生成的 TemplateHaskell
代码中使用它们,但这是不必要的(那里没有通用的东西)。