代码之家  ›  专栏  ›  技术社区  ›  David Unric

部分应用程序的说明-联接

  •  5
  • David Unric  · 技术社区  · 12 年前

    为什么具有不同签名的函数的部分应用有效?

    Control.Monad.join 例如:

    GHCi> :t (=<<)
    (=<<) :: Monad m => (a -> m b) -> m a -> m b
    GHCi> :t id
    id :: a -> a
    GHCi> :t (=<<) id
    (=<<) id :: Monad m => m (m b) -> m b
    

    为什么它接受 id :: a -> a 代替 (a -> m b) 争论,因为他们显然不同?

    3 回复  |  直到 12 年前
        1
  •  11
  •   Matt Fenwick sagarcool89    12 年前

    =<< 的类型签名表示第一个参数是 a (任何东西)到 b

    m b 算什么,对吧?所以我们可以代替 百万 以下为:

    (=<<) :: Monad m => (m b -> m b) -> m (m b) -> m b
    

    id s类型表示它是从任何事物到相同任何事物的函数。所以如果我们进入 百万 (不要忘记monad约束),我们得到:

    id :: Monad m => m b -> m b
    

    然后您可以看到类型匹配。

        2
  •  3
  •   Luis Casillas    12 年前

    这里使用一些有用的概念:

    1. 任何带有变量的类型 a 可以通过替换的每个实例转换为不同的类型 与任何其他类型 t 。所以如果你有 a -> b -> c ,可以获取类型 a -> d -> c 或类型 a -> b -> Int 通过替换 b 具有 d c 具有 Int 分别地
    2. 任何两种可以通过替换相互转换的类型都是等效的。例如 a -> b c -> d 是等效的( ~ c , b ~ d )。
    3. 如果类型 可以转换为类型 t' 但是 不要 无法转换回 ,然后我们说 不要 是一个 专业化 属于 例如 a -> a a->b

    现在,有了这些非常有用的概念,你的问题的答案很简单:即使函数的“原生”类型不完全匹配,它们也是兼容的,因为它们可以重写或专门化以获得完全匹配。Matt Fenwick的回答显示了专门为这个案子做这件事。

        3
  •  2
  •   Ramon Snir    12 年前

    它试图统一 a 具有 m b ,并简单地决定 必须是 百万 ,因此的类型 (=<<) (假设 a ~ m b )是 Monad m => (mb -> m b) -> m (m b) -> m b ,并且一旦您将其应用于 id ,剩下的是 Monad m => m (m b) -> m b