我对 Haskell 很陌生,所以如果我遗漏了关键概念,请指出。
假设我们有这两个函数:
fact n
| n == 0 = 1
| n > 0 = n * (fact (n - 1))
fact
的多态类型是 (Eq t, Num t) => t -> t
因为 n
用于 if 条件,并且 n 必须是有效类型才能进行 ==
检查。因此 t
必须是 Number
并且 t
可以是类约束 Eq t
内的任何类型fib n
| n == 1 = 1
| n == 2 = 1
| n > 2 = fib (n - 1) + fib (n - 2)
那为什么
fib
的多态类型是 (Eq a, Num a, Num t) => a -> t
呢?看不懂,求帮助。
最佳答案
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 -> Bool
和 1 :: Num a => a
。但是 输入 n
从不直接用于输出 。事实上,最后一行有 fib (n-1) + fib (n-2)
,但在这里 我们使用 n-1
和 n-2
作为新调用 的输入。所以这意味着我们可以安全地假设输入类型和输出类型是独立的。输出类型,仍然有一个类型约束: Num t
:这是因为我们在前两种情况下返回 1
和 1 :: Num t => t
,我们还返回两个输出的相加: fib (n-1) + fib (n-2)
,所以再次 (+) :: Num t => t -> t -> t
。
关于function - 两个相似的函数如何在 Haskell 中具有不同的多态类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45459637/