【问题标题】:Error: "...because type variable ‘t’ would escape its scope" using package "servant" in Haskell错误:“...因为类型变量‘t’会在 Haskell 中使用包‘servant’逃逸”
【发布时间】:2017-12-10 01:07:29
【问题描述】:

我正在构建代码以使用 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)

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

【问题讨论】:

  • 我尝试在 ghc 8.2.2 上使用 NoMonomorphismRestriction 编译您的代码,它似乎工作得很好。
  • @JohnWiegley 我不需要在运行时成为t 动态。你能告诉我我必须使用的代码吗?我对Proxy t的理解还很有限,所以我真的需要一些帮助。
  • @Rufflewind 使用NoMonomorphismRestriction 为我解决了这个问题。如果你添加一个快速的答案,我会接受它:)
  • @Sh4pe 既然给出了这个问题的正确答案,我已经删除了我不准确的答案。

标签: haskell


【解决方案1】:

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

我复制了您使用在线 GHC 7.10 编译器看到的错误消息,因此 GHC 的错误似乎有所改善。在 GHC 8.2 和 7.10 中,如果启用 NoMonomorphismRestriction,错误就会消失,从而解决问题。

我最好的猜测是,当启用单态限制时,queryFunction1 :&lt;|&gt; 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

【讨论】:

  • 非常感谢您的回答!
猜你喜欢
  • 2015-06-10
  • 1970-01-01
  • 2017-04-30
  • 1970-01-01
  • 2012-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-23
相关资源
最近更新 更多