如何在Haskell中跟踪类型推断?

时间:2016-10-15 18:16:02

标签: haskell

无法真正遵循下面的类型推断,其中案例1有效但案例2失败,为什么?

ghci> :t sqrt . maximum . map (+1)   -- case 1

(Floating c, Ord c) => [c] -> c

ghci> :t sqrt . maximum . map length -- case 2

Could not deduce (Floating Int) arising from a use of ‘sqrt’
from the context (Foldable t)
bound by the inferred type of it :: Foldable t => [t a] -> Int

@EDIT

在OOP上,Num通常是subtypes所有Int的下限。 FloatInt。因此,如果Num是限定类型,则Int将被推断,但反之亦然。

此外,在类C语言中,内置数字转换可以自动满足从较低精度到较高精度的情况。从FloatNum

相比之下,在HM type system的Haskell上,class是其所有instances的{​​{1}},例如IntsubclassesFloating例如Num。合格类型可以在祖先和后代之间进行双推理,例如从IntFloatingInt,反之亦然,但不在FloatingInt之间。

要解决案例2,Num应首先适应fromIntegral Data.List.genericLength或使用Num生成Floating - 推理限定类型sqrt要求的ghci> :t (+) Num a => a -> a -> a ghci> :t 1.1 Fractional a => a ghci> :i Fractional class Num a => Fractional a instance Fractional Float instance Fractional Double ghci> :t 1 Num a => a ghci> :t length [1] Int ghci> :i Int instance Num Int instance Real Int instance Integral Int ghci> :t 1.1 + 1 -- case 1 Fractional a => a ghci> :t 1.1 + length [1] -- case 2 No instance for (Fractional Int) arising from the literal ‘1.1’

让我们应用上述要点来遵循下面的类型推断,

class A
{
public:
    virtual void func();
    virtual void func2();
}

class B : public A
{
public:
    void func();
}
class C : public A
{
public:
    void func2()
}

1 个答案:

答案 0 :(得分:4)

1可以是任何类型的数字,+可以使用任何类型的数字。 maximum也是如此。因此maximum . map (+1)是一个函数,可以获取任何类型的数字列表,并生成与其结果相同类型的数字。这包括整数和浮点数。

但是length会专门生成Int。它不能产生任何其他类型的数字。因此maximum . map length可以获取任何列表并生成Int类型的结果,而不是任何其他数字类型。

现在sqrt需要将其参数作为浮点数。因此,在第一种情况下,类型推断表明您必须提供浮点数列表,因此maximum . map (+1)的结果将是可以传递给sqrt的浮点数。

然而,第二种情况根本无法奏效,因为Int不是浮点类型而maximum . map length不能生成除Int以外的任何内容。所以这会导致错误。

您可以使用fromIntegral函数将length的结果转换为任何数字类型,以使第二个代码有效。