haskell - 指定嵌套类型变量约束在 Haskell 中属于同一实例

标签 haskell typeclass

以下内容显式使用 FooA 作为 (#)queryP 中的类型,按预期进行编译:

{-# LANGUAGE RankNTypes, ScopedTypeVariables #-}
module Foo where

class Foo a where

newtype FooParser a = FooParser { (#) :: FooA -> (a, FooA) }

queryP :: (FooA -> a) -> FooParser a
queryP f = FooParser $ \(b :: FooA) -> (f b, b)

data FooA = FooA Int
instance Foo FooA where

但是当我尝试使用类型类 Foo 定义 FooParserqueryP 时,如下所示:

{-# LANGUAGE RankNTypes, ScopedTypeVariables #-}
module Foo where

class Foo a where

newtype FooParser a = FooParser { (#) :: Foo b => b -> (a, b) }

queryP :: Foo b => (b -> a) -> FooParser a
queryP f = FooParser $ \(b :: Foo b => b) -> (f b, b)

我收到一个无法推断的错误:

Foo.hs:11:52:
    Could not deduce (b ~ b1)
    from the context (Foo b)
      bound by the type signature for
                 queryP :: Foo b => (b -> a) -> FooParser a
      at Foo.hs:10:11-42
    or from (Foo b1)
      bound by a type expected by the context: Foo b1 => b1 -> (a, b1)
      at Foo.hs:11:12-53
      ‘b’ is a rigid type variable bound by
          the type signature for queryP :: Foo b => (b -> a) -> FooParser a
          at Foo.hs:10:11
      ‘b1’ is a rigid type variable bound by
           a type expected by the context: Foo b1 => b1 -> (a, b1)
           at Foo.hs:11:12
    Relevant bindings include
      b :: Foo b => b (bound at Foo.hs:11:26)
      f :: b -> a (bound at Foo.hs:11:8)
      queryP :: (b -> a) -> FooParser a (bound at Foo.hs:11:1)
    In the expression: b
    In the expression: (f b, b)

如何指定 queryP 中 lambda 函数中的 b 与第一个中的类型类 Foo 的实例相同f 的参数?

最佳答案

在类型定义中

newtype FooParser a = FooParser { (#) :: Foo b => b -> (a, b) }

类型变量 b普遍绑定(bind)在更高等级的类型中;即新引入的选择器函数的类型(#)

*Foo> :t (#)
(#) :: Foo b => FooParser a -> b -> (a, b)

但这意味着当你构造 FooParser a 时,传递给构造函数的函数必须键入 b -> (a, b)对于 b任意选择(只要 Foo b 成立):

*Foo> :t FooParser
FooParser :: (forall b. Foo b => b -> (a, b)) -> FooParser a

但是,在 queryP给你一个 b -> a 类型的函数对于b一些选择(b 由调用者选择,唯一的限制是 Foo b 将保留)。

所以如果我设置b ~ b1并调用queryP ,这意味着我正在向您传递一个 f :: b1 -> a 类型的函数。然后你必须返回给我一个 forall b. (Foo b) => b -> (a, b) 类型的函数。 (包装在构造函数 FooParser 中)。

你不能只使用f为此,对于 b 的任何选择除了 b1 (例如 b ~ b2 )它的类型不正确。

在目前的形式下,您基本上只能使用 Foo 中的函数。类和参数充分的多态函数来构造您的 forall b. (Foo b) => b -> (a, b)功能。根据您想要执行的操作,您可以

  • 更改queryP这样它就需要一个多态函数:
queryP :: (forall b. Foo b => (b -> a)) -> FooParser a
queryP f = FooParser $ \b -> (f b, b)
  • 更改FooParser这样b是存在的约束:
{-# LANGUAGE ExistentialQuantification #-}
data FooParser a = forall b. Foo b => FooParser { (#) :: b -> (a, b) }

请注意,这两个更改意味着(并且暗示)非常不同的事情。

关于haskell - 指定嵌套类型变量约束在 Haskell 中属于同一实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31799691/

相关文章:

haskell - 是否有可能有一个 "local"类型类实例?

scala - Shapeless 中 TypeClass 特征的 emptyCoproduct 和 coproduct 方法的目的是什么

haskell - 你能在 Haskell 中为整个类而不是类型创建一个类的实例吗?

haskell - 1GB Vector,Vector.Unboxed会麻烦,Vector.Storable会不会麻烦?

haskell - 弱化对 2 级类型的约束

haskell - 函数组合和 forall'ed 类型

haskell - 自己的数据类型 - 它们与 native 数据类型之间的转换

haskell - Return语句在Haskell中如何工作?

arrays - 消除有界类型的 Haskell 数组边界检查?

haskell - 将具有有效功能空间(如 ML)的语言核心嵌入到 Haskell 中有多实用?