【问题标题】:Why doesn't this type check?为什么这种类型不检查?
【发布时间】:2018-12-29 00:01:20
【问题描述】:
class Foo t where
  foo :: t

bar :: Binary t => t -> ()
bar = undefined

repro :: (Binary t, Foo t) => Proxy t -> ()
repro _proxy =
  bar (foo :: t)

编译器抱怨:

  • 由于使用“bar”而无法推断出 (Binary t0) 从上下文:(二进制 t,Foo t) 受类型签名的约束: 复制 :: forall t。 (二进制 t, Foo t) => 代理 t -> ()

  • 无法推断 (Foo t2) 由使用“foo”引起 从上下文:(二进制 t,Foo t) 受类型签名的约束: 复制 :: forall t。 (二进制 t, Foo t) => 代理 t -> ()

具体来说,我很惊讶它没有看到我将t 传递给bar,并创建了一个t0 类型var。 t2 更加神秘,因为foo 被显式注释为t

【问题讨论】:

    标签: haskell


    【解决方案1】:

    为了完整起见,这也可以在没有扩展的情况下处理。这里的关键技巧是编写一个类型更多限制的函数,将Proxy 的类型参数与Foo 实例连接起来。所以:

    -- most general possible type is Foo b => a -> b
    fooForProxy :: Foo t => proxy t -> t
    fooForProxy _proxy = foo
    
    -- I've changed Proxy to proxy here because that's good practice, but everything
    -- works fine with your original signature.
    repro :: (Binary t, Foo t) => proxy t -> ()
    repro = bar . fooForProxy
    

    当然,现代的方法是使用甚至 更多 扩展来完全消除代理:

    {-# LANGUAGE TypeApplications #-}
    {-# LANGUAGE AllowAmbiguousTypes #-}
    {-# LANGUAGE ScopedTypeVariables #-}
    
    repro :: forall t. (Binary t, Foo t) => ()
    repro = bar @t foo
    

    调用repro 将再次需要类型应用程序,如repro @Int 或其他。

    【讨论】:

      【解决方案2】:

      默认情况下,类型变量的范围不是这种方式。函数签名中的t和函数体中的t不一样。你的代码相当于这个:

      repro :: (Binary t, Foo t) => Proxy t -> ()
      repro _proxy =
        bar (foo :: a)
      

      您需要启用 ScopedTypeVariables 扩展,并添加显式 forall t

      {-# LANGUAGE ScopedTypeVariables #-}
      
      repro :: forall t. (Binary t, Foo t) => Proxy t -> ()
      repro _proxy =
        bar (foo :: t)
      

      【讨论】:

        【解决方案3】:

        你可能需要打开ScopedTypeVariables扩展然后使用

        repro :: forall t. (Binary t, Foo t) => Proxy t -> ()
        repro _proxy = bar (foo :: t)
        

        否则,foo :: t 中的trepro 签名中的另一个t 无关。本质上,foo :: t 等同于 foo :: forall a. a

        这可以说是 Haskell 定义中最不受欢迎的功能之一,ScopedTypeVariables 非常受欢迎,因为它可以解决这个问题。 (在我看来,它应该默认开启。)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-04-14
          • 1970-01-01
          • 2012-02-23
          • 2019-12-23
          • 1970-01-01
          • 1970-01-01
          • 2011-03-17
          • 1970-01-01
          相关资源
          最近更新 更多