Haskell:这些表达方式有哪些类型(如果有的话)



我是Haskell的新手,我正在做一些练习来尽可能多地学习类型,但有些问题对我来说真的很困惑。我正在努力的练习如下:

以下表达式有哪些类型?如果表达式没有类型,请尽可能多地声明。也 请务必在需要时声明必要的类限制。

5 + 8 :: ?
(+) 2 :: ?
(+2) :: ?
(2+) :: ?

我知道 5 + 8 将返回一个 Int,但其他表达式不是它们自己的有效表达式。这是否意味着它们没有类型,或者我应该将它们视为函数(f :: Int -> Int)(f x = x + 2)?

首先,答案:

  • 5 + 8具有可以专门用于Intforall a. Num a => a类型。
  • (+) 2(2 +)是相同的,并且都具有可以专门用于Int -> Intforall a. Num a => a -> a类型。
  • (+ 2)是不同的,但也具有可以专门用于Int -> Intforall a. Num a => a -> a类型。
  • (+)具有可以专门用于Int -> Int -> Intforall a. Num a => a -> a -> a类型。

有关进一步说明,请继续阅读。


一个文字,多种类型

在 Haskell 中,像114514这样的数字文字没有像Int这样的具体类型。这很好,因为我们有许多不同类型的数字,包括。IntIntegerFloatDouble等等,我们不希望每种类型都有不同的符号。

文字51145141919810都具有以下类型

forall a. Num a => a

你可以这样读:"对于任何类型a,如果aNum类型类的实例,那么该值可以具有a类型。IntIntegerFloatDouble都是Num的实例,并且因为Haskell具有(相对)强的类型推断, 在不同的上下文中,它将专门针对具体类型,例如Int.

那么什么是类型类呢?

类型类

我们在Haskell中表达某些类型"支持"某些操作的方式是通过类型类。类型类是一组函数签名,没有真正的实现。它们代表我们想要对某些类型进行的操作(例如Num表示我们想要对数值类型进行的操作),但对不同类型的实际实现可能会有所不同(整数和浮点数的实际计算确实不同)。

我们可以使类型成为类型类的instance(请注意,这与面向对象编程中的实例和类无关),通过实际为该类型定义这些函数。通过这种方式,我们定义了此类型来支持这些操作。

Num是类型类之一,表示对数值运算的支持。它部分定义如下(为了减少冗长,我没有在这里放完整的):

class Num a where
(+) :: a -> a -> a
(-) :: a -> a -> a
(*) :: a -> a -> a

你可以看到,在签名中,我们有a而不是真正的具体类型,这些函数被称为多态的,也就是说,它们是泛型的,可以专门用于不同的类型。

例如,如果ab都是Ints,那么a + b也有类型Int,因为 haskell 推断我们在这里使用的+应该是为Int定义的,因为它的两个参数都是Ints。

因此,如果某个类型是Num的实例,则意味着为该类型定义了+-*运算符。作为Num的实例意味着支持这些运营商。

<小时 />

部分

Haskell的一个好处是它(相对)灵活的中缀运算符。在 Haskell 中,中缀运算符只不过是带有中缀符号(这只是一种语法糖)的普通函数。我们还可以以前缀方式使用中缀运算符。例如,5 + 8等效于(+) 5 8

看来你对(+) 5(+5)(5+)感到困惑。请记住,如果我们在中缀函数的两侧都加上括号,我们就会将其设为前缀。而且你可能已经知道,前缀函数可以部分应用,也就是说,只给函数一些参数,所以它变成了一个参数较少的函数,以后要给出。(+) 5意味着我们通过只给出它的第一个参数来部分应用(+),所以它变成了一个等待另一个参数的函数,或者最初是它的第二个参数。我们可以将(+) 5应用于8,使其变为((+) 5) 8,这相当于5 + 8

另一方面,(5+)(+5)称为,这是中缀运算符的另一种语法糖。(5+)意味着您填充了运算符的左侧,它变成了等待其右侧的功能。(5+) 8表示5 + 8(+) 5 8(+5)是翻转的,即你填充了右侧,所以它是一个等待左侧的功能。(+5) 8表示8 + 5(+) 8 5


Haskell是一种与你可能学过的其他语言非常不同的语言;每个编译的表达式都有一个类型。函数是一流的,每个函数也有一个类型。类型思维将真正有助于您的学习进度。

在哈斯克尔:

  • 运算符只是函数
  • 函数可以提供比声明更少的参数
  • 括号可用于消除参数的顺序和组件的歧义

综合起来,这意味着:

  • (+) 只是 + 函数,并且还需要 2 个参数
  • (1 +) 是提供第一个参数的函数,将再取一个参数
  • (+ 2) 是另一个提供参数的函数,但这次是第二个。它还等待另一个论点

相关内容

最新更新