错误:" ...因为类型变量't'会逃避其范围"使用包" servant"在哈斯克尔

时间:2017-12-10 01:07:30

标签: haskell

我使用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)

是否有人建议我如何避免此错误并使我的代码正常工作?

1 个答案:

答案 0 :(得分:1)

我无法重现您使用GHC 8.2.2看到的错误。相反,我得到了一些“与单态限制重载的签名冲突”的内容。

我重现了您使用在线GHC 7.10编译器看到的错误消息,因此GHC的错误似乎有所改善。在GHC 8.2和7.10中,如果启用NoMonomorphismRestriction,则错误消失,以便解决问题。

我最好的猜测是,当启用单态限制时,queryFunction1 :<|> queryFunction2的类型被假定为完全单态(根本没有类型参数),因为你没有声明它的类型签名(不是你可以在这个案例!)。这与queryFunction1queryFunction2的类型签名冲突,两者都包含类型参数。

这是一个重现确切问题的最小测试:

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