两个相似的函数如何在Haskell中具有不同的多态类型?

时间:2017-08-02 11:29:42

标签: function haskell types polymorphism fibonacci

我对Haskell来说几乎是新手,所以如果我缺少关键概念,请指出。

让我们说我们有这两个功能:

fact n
     | n == 0 = 1
     | n > 0  = n * (fact (n - 1))

fact的多态类型为 (Eq t, Num t) => t -> t 因为n用于if条件且n必须是有效类型才能执行{{1}检查。因此,==必须是t,而Number可以是类约束t中的任何类型

Eq t

那为什么fib n | n == 1 = 1 | n == 2 = 1 | n > 2 = fib (n - 1) + fib (n - 2) 的多态类型是 fib

我不明白,请帮助。

2 个答案:

答案 0 :(得分:7)

Haskell总是旨在派生大多数泛型类型签名。

现在fact,我们知道输出的类型应该与输入的类型相同:

fact n | n == 0 = 1
       | n > 0  = n * (fact (n - 1))

这是由于最后一行。我们使用n * (fact (n-1))。所以我们使用乘法(*) :: a -> a -> a。因此乘法采用相同类型的两个成员并返回该类型的成员。由于我们乘以n并输入n,因此输出与输入的类型相同。由于我们使用n == 0,因此我们知道(==) :: Eq a => a -> a -> Bool,这意味着该输入类型应该包含Eq a =>,还有0 :: Num a => a。因此,结果类型为fact :: (Num a, Eq a) => a -> a

现在fib,我们看到:

fib n | n == 1 = 1
      | n == 2 = 1
      | n > 2  = fib (n - 1) + fib (n - 2)

现在我们知道,对于n,类型约束又是Eq a, Num a,因为我们使用n == 1(==) :: Eq a => a -> a -> Bool1 :: Num a => a。但输入n永远不会直接用于输出。实际上,最后一行有fib (n-1) + fib (n-2),但在这里我们使用n-1n-2作为新来电的输入。这意味着我们可以安全地假设输入类型和输出类型独立地起作用。输出类型仍有类型约束:Num t:这是因为前两个案例返回11 :: Num t => t,我们还返回两个输出:{ {1}},再次fib (n-1) + fib (n-2)

答案 1 :(得分:5)

不同之处在于,在fact中,您直接在算术表达式中使用该参数,该算术表达式构成了最终结果:

fact n | ...  = n * ...

IOW,如果你写出扩展的算术表达式,其中会出现n

fact 3  ≡  n * (n-1) * (n-2) * 1

这修复了参数必须与结果具有相同类型的原因,因为

(*) :: Num n => n -> n -> n

fib中不是这样:这里的实际结果只包含文字和 sub - 结果。 IOW,扩展的表达式看起来像

fib 3  ≡  (1 + 1) + 1

此处没有n,因此参数和结果之间不需要统一。

当然,在这两种情况下,你也使用n来决定这个算术表达式的外观,但为此你刚刚使用了与文字相等的比较,其类型没有与最终结果相关联。

请注意,您还可以为fib提供类型保留签名:(Eq a, Num a, Num t) => a -> t严格地比(Eq t, Num t) => t -> t更通用。相反,您可以通过使用转换函数将fact设置为不需要输入和输出的fact' :: (Eq a, Integral a, Num t) => a -> t fact' = fromIntegral . fact

Integer

这虽然没有多大意义,因为fact几乎是唯一可以在Integer中可靠使用的类型,但要在上述版本中实现这一点,您需要启动与fact'' :: (Eq t, Integral a, Num t) => a -> t fact'' = fact . fromIntegral 一起出去。因此,如果有的话,您应该执行以下操作:

Int -> Integer

这也可以用作(Eq t, Num t) => t -> t,这有点明智。

建议只保留签名fact,并且只在实际需要的位置添加转换操作。或者真的,我建议根本不使用npm install --save react-bootstrap - 这是一个非常昂贵的功能,在实践中几乎没有用过;大多数天真地以阶乘结束的应用程序实际上只需要binomial coefficients之类的东西,而且这些应用程序可以在没有因子的情况下更有效地实现。