我使用servant构建用于查询REST API的代码。对于某些端点,我希望返回值依赖于某种类型t
。当我尝试使用:<|>
组合多个此类API时,出现编译错误。
我试图建立一个问题的简化示例。可悲的是,最短的版本仍然不是很短。这是我的代码:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
module Sana.ArangoDB.RTest where
import Servant.API
import Servant.Client
import Data.Aeson.Types (typeMismatch)
import Data.Proxy (Proxy(..))
import Data.Yaml (FromJSON(..), (.:))
import qualified Data.Yaml as Y
data SomeStructure t = SomeStructure { _a :: Bool , _b :: t }
instance FromJSON t => FromJSON (SomeStructure t) where
parseJSON (Y.Object v) = SomeStructure <$> v .: "a" <*> v .: "b"
parseJSON i = typeMismatch "SomeStructure" i
type MyAPI t = "api" :> Header "SomeHeader" String :> Get '[JSON] (SomeStructure t)
type MyOtherAPI t = "api2" :> Header "SomeHeader" String :> Get '[JSON] (SomeStructure t)
type TheAPI t = MyAPI t :<|> MyOtherAPI t
theAPI :: Proxy (TheAPI t)
theAPI = Proxy
queryFunction1 :: (FromJSON t ) => Maybe String -> ClientM (SomeStructure t)
queryFunction2 :: (FromJSON t ) => Maybe String -> ClientM (SomeStructure t)
queryFunction1 :<|> queryFunction2 = client theAPI
然而,这不会编译。我得到的错误是:
• Couldn't match type ‘t0’ with ‘t’
because type variable ‘t’ would escape its scope
This (rigid, skolem) type variable is bound by
the inferred type for ‘queryFunction1’:
FromJSON t => Maybe String -> ClientM (SomeStructure t)
at /Users/david/devel/sana/src/Sana/ArangoDB/RTest.hs:31:1-50
Expected type: Maybe String -> ClientM (SomeStructure t)
Actual type: Maybe [Char] -> ClientM (SomeStructure t0)
是否有人建议我如何避免此错误并使我的代码正常工作?
答案 0 :(得分:1)
我无法重现您使用GHC 8.2.2看到的错误。相反,我得到了一些“与单态限制重载的签名冲突”的内容。
我重现了您使用在线GHC 7.10编译器看到的错误消息,因此GHC的错误似乎有所改善。在GHC 8.2和7.10中,如果启用NoMonomorphismRestriction
,则错误消失,以便解决问题。
我最好的猜测是,当启用单态限制时,queryFunction1 :<|> queryFunction2
的类型被假定为完全单态(根本没有类型参数),因为你没有声明它的类型签名(不是你可以在这个案例!)。这与queryFunction1
和queryFunction2
的类型签名冲突,两者都包含类型参数。
这是一个重现确切问题的最小测试:
h :: Show z => (Maybe z, Maybe z)
h = (Nothing, Nothing)
f :: Show x => Maybe x
g :: Show y => Maybe y
(f, g) = h
要重现此类错误,您需要某种约束(例如Show
)和变量周围的某种类型构造函数(例如Maybe
)。
您在GHC 7.10中遇到的错误是:
source_file.hs:6:1:
Couldn't match type ‘z0’ with ‘x’
because type variable ‘x’ would escape its scope
This (rigid, skolem) type variable is bound by
the inferred type for ‘f’: Show x => Maybe x
at source_file.hs:6:1-10
Expected type: forall x. Show x => Maybe x
Actual type: Maybe z0
When checking that ‘f’ has the specified type
f :: forall x. Show x => Maybe x
Probable cause: the inferred type is ambiguous
source_file.hs:6:1:
Couldn't match type ‘z0’ with ‘y’
because type variable ‘y’ would escape its scope
This (rigid, skolem) type variable is bound by
the inferred type for ‘g’: Show y => Maybe y
at source_file.hs:6:1-10
Expected type: forall y. Show y => Maybe y
Actual type: Maybe z0
When checking that ‘g’ has the specified type
g :: forall y. Show y => Maybe y
Probable cause: the inferred type is ambiguous
source_file.hs:6:10:
No instance for (Show z0) arising from a use of ‘h’
The type variable ‘z0’ is ambiguous
Relevant bindings include
f :: Maybe z0
(bound at source_file.hs:6:2)
g :: Maybe z0
(bound at source_file.hs:6:5)
Note: there are several potential instances:
instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
instance Show Ordering -- Defined in ‘GHC.Show’
instance Show Integer -- Defined in ‘GHC.Show’
...plus 22 others
In the expression: h
In a pattern binding: (f, g) = h