【问题标题】:Polymorphic types in HaskellHaskell 中的多态类型
【发布时间】:2018-01-11 04:15:25
【问题描述】:

我遇到了这个功能

iter p f x = if (p x) then x else (iter p f (f x))

我想我会尝试自己定义多态类型以理解这个概念。

我的想法如下:

函数有3个参数,所以我们有t1 -> t2 -> t3 -> T

  1. p 在 if 条件中使用,因此它必须返回 bool,因此返回 t1 = a -> Bool

  2. f 也与 p 是同一类型,因为它在 else 块中作为参数传递,因此 t2 = a -> Bool

  3. x 在 if 条件中使用,因此它必须返回一个布尔值,因此 t1 = a -> Bool

但是当我检查 ghci 中的类型时,他们给我的类型是

iter :: (t -> Bool) -> (t -> t) -> t -> t

谁能解释一下这背后的原因。

谢谢

【问题讨论】:

    标签: function haskell types polymorphism polymorphic-functions


    【解决方案1】:

    函数有3个参数,所以我们有t1 -> t2 -> t3 -> T

    这是正确的起点。

    p 在 if 条件中使用,所以它必须返回一个 bool,因此 t1 = a -> Bool

    正确。

    f 也是与 p 相同的类型,因为它在 else 块中作为参数传递,因此 t2 = a -> Bool

    不正确。 f 永远不会以与 p 相同的方式使用。在 else 块中,f 被应用到x,结果作为最后一个参数传递给iter。由此我们知道f x 必须与x 的类型相同,所以f :: a -> a

    x 在 if 条件中使用,因此它必须返回一个 bool,因此 t1 = a -> Bool

    不正确。在 if 条件中,x 仅用作p 的参数。你在上面建立了p :: a -> Bool。因此x :: a

    但是当我检查 ghci 中的类型时,他们给我的类型是

    iter :: (t -> Bool) -> (t -> t) -> t -> t

    正确。您也可以将 t 替换为 a 以保持符号一致 - 我们在上面使用了 a

    iter :: (a -> Bool) -> (a -> a) -> a -> a
    

    【讨论】:

    • 我明白了,所以每次在函数内部将两个参数相互应用时,两个参数必须是相同的类型?例如,f x 在 else 中传递,这意味着 fx 必须是相同类型才能调用 iter 函数?
    • 不,一般来说不是。这是一个特例,因为我们知道f x 的类型必须与x 相同。我们知道这是因为两者都作为第三个参数传递给iter。编辑:对不起,误读了,我应该说不,一点也不 :) f :: a -> ax :: a 所以它们根本不是同一类型。 f 是一个必须返回 a 的函数,我们将x :: a 作为参数传递给f :: a -> a
    • 谢谢,我真的很喜欢你和威廉的回答。他们俩都为我清除了很多。不能选择接受哪一项。但是我给你这个,因为我接受了他的最后一个问题:)谢谢你的时间
    【解决方案2】:

    让我们再评估一下:

    iter p f x = if (p x) then x else (iter p f (f x))
    

    iter 接受三个参数(从技术上讲,每个函数都接受一个参数,但让我们跳过细节)。所以它确实有一个类型t1 -> t2 -> t3 -> t

    现在在if-then-else 语句中,我们看到(p x) 这意味着p x 必须计算为布尔值。所以这意味着:

    t1 ~ t3 -> Bool
    

    接下来我们在then 语句中看到x。这可能看起来不重要,但它是:这意味着输出类型tt3的输出类型相同,所以:

    t3 ~ t
    

    现在这意味着我们已经推导出 iter 具有以下类型:

    iter :: (t3 -> Bool) -> t2 -> t3 -> t3
    

    现在我们在else 语句中看到调用:

    iter p f (f x)
    

    这意味着f 是一个函数f :: t4 -> t5。由于它以x 作为输入,它的输入类型应该是t3,并且由于(f x) 的结果被传递给iter 函数(即不是 本身相同的“接地”iter 功能)。所以我们必须检查调用:

    iter :: (u3 -> Bool) -> u2 -> u3 -> u3  -- call
    

    现在既然我们用iter p f (f x) 调用它,我们肯定知道u3 ~ t3: 因为p 具有t3 -> Bool 类型。因此,它进一步基于:

    iter :: (t3 -> Bool) -> u2 -> t3 -> t3  -- call
    

    正弦(f x)作为第三个参数,我们知道f x的结果类型也应该是t3。所以f 的类型为f :: t3 -> t3。因此我们得出结论,iter 具有以下类型:

    iter :: (t3 -> Bool) -> (t3 -> t3) -> t3 -> t3
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多