指定嵌套类型变量约束在Haskell中具有相同的实例

时间:2015-08-04 02:25:07

标签: 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 中的类型按预期编译:

FooParser

但是,当我尝试使用类型queryP来定义Foo{-# 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)

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

b

如何指定queryP中lambda函数中的Foof的第一个参数中的类型 $('.date-picker').hover(function(){ if(!$(this).hasClass('hasDatepicker')){ $(this).addClass('hasDatepicker'); $(this).datepicker(); } }); 的实例相同?< / p>

1 个答案:

答案 0 :(得分:5)

在类型定义

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

类型变量b通常以更高级别的类型绑定;即新引入的选择器函数(#)的类型是

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

但这意味着当您构建FooParser a时,传递给构造函数的函数必须在b -> (a, b)处键入{strong>任何选择的b(如只要Foo b持有):

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

但是,在queryP中,b -> a某些选择b提供了b类型的函数(Foo bb ~ 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) } ,以便def autocomplete_property_address properties = Property.address_theme_joint_table(current_user.company.theme_name,"%#{params[:term]}%") #render properties render :json => properties.map{ |property|{:id => property.id, :address => property.address}} end 存在受限:
<%= text_field_tag :search, params[:search], class: "search-query", placeholder: "Address search", type: "search", data: {autocomplete: autocomplete_property_address_properties_path}, :id_element => '', :update_elements => {} %> 

请注意,这两项变化意味着(并暗示)非常不同的事情。