【问题标题】:How to reuse a type variable in an inner type declaration如何在内部类型声明中重用类型变量
【发布时间】:2015-01-08 11:26:07
【问题描述】:

作为我学习 Haskell 过程的一部分,我喜欢明确键入函数的类型声明。我希望能够对 where 子句中定义的函数执行此操作,但我不知道如何指定 where 子句中的类型变量应该与外部类型声明中的某个类型变量表示相同的类型。比如下面的代码:

foo :: (a -> a) -> a -> a
foo f arg = bar arg
  where
    bar :: a -> a
    bar a = f a

产生此错误:

src\Test.hs:7:14:
    Couldn't match expected type `a' against inferred type `a1'
      `a' is a rigid type variable bound by
          the type signature for `foo' at src\Test.hs:3:8
      `a1' is a rigid type variable bound by
           the type signature for `bar' at src\Test.hs:6:11
    In the first argument of `f', namely `a'
    In the expression: f a
    In the definition of `bar': bar a = f a

如何表示 bar 的第一个参数应该与 foo 的第二个参数具有相同的类型,以便我可以将 f 应用于它?

谢谢。

【问题讨论】:

    标签: haskell


    【解决方案1】:

    我认为您通常可以使用 GHC 支持的ScopedTypeVariables 执行此操作。这当然可以编译:

    {-# LANGUAGE ScopedTypeVariables #-}
    foo :: forall a. (a -> a) -> a -> a
    foo f arg = bar arg
      where
        bar :: a -> a
        bar a = f a
    

    注意“forall a”。

    【讨论】:

      【解决方案2】:

      还有另一种解决方法。不要在内部函数bar 中引用f,而是扩展bar 以接受f 作为第一个参数并在父函数中使用部分应用程序。

      foo :: (a -> a) -> a -> a
      foo f arg = (bar f) arg
        where
          bar :: (a -> a) -> a -> a
          bar f a = f a
      

      它不需要 ScopedTypeVariables 或显式类型检查代码作为其他答案。

      说明

      为了清楚起见,让我们将bar 中的类型参数更改为b,并重命名它的参数。

      foo :: (a -> a) -> a -> a
      foo f arg = bar arg
        where
          bar :: b -> b
          bar x = f x
      

      Haskell 抱怨是因为 bar 被注释为 b -> b(对于任何任意类型 b),但 f x 试图将 b 类型的参数应用于 a -> a 类型的函数(对于一个特定的绑定a)。换句话说,内部函数并不像它的类型注释所宣传的那样通用。

      f 传递给bar 意味着对于表达式(bar f),类型变量b 绑定到与a 相同的类型。

      更简单

      最后,在不改变任何其他内容的情况下,如果您愿意省略内部函数 bar 的类型签名,Haskell 将完全按照您想要的方式推断其类型。也就是说,由于bar 应用来自父函数foof,所以bar 的类型将重用来自foo 类型的类型参数a

      foo :: (a -> a) -> a -> a
      foo f arg = bar arg
        where
          -- Type: bar :: a -> a
          bar a = f a
      

      【讨论】:

        【解决方案3】:

        This answer 到另一个问题显示了一个技巧,如果您不想使用 ScopedTypeVariables 扩展。

        【讨论】:

          【解决方案4】:
          猜你喜欢
          • 2012-09-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-09-28
          • 1970-01-01
          • 1970-01-01
          • 2015-04-28
          • 1970-01-01
          相关资源
          最近更新 更多