类型构造函数是否可以被视为函数式编程语言中的类型



我正在学习Haskell编程语言,我有Scala和Java开发人员的背景。

我读过类型构造函数背后的理论,但我不明白它们是否可以被视为类型。我的意思是,在Scala中,您使用关键字classtrait来定义类型构造函数。想想List[T]Option[T]。同样在Haskell中,您使用了用于定义新类型的相同关键字data

那么,类型构造函数也是类型吗?

让我们来看看一个类比:函数。在数学的某些分支中,函数被称为值构造函数,因为它们就是这样做的:你把一个或多个值放进去,它们从中构造一个新值。

类型构造函数是完全相同的东西,除了在类型级别:你把一个或多个类型放进去,他们从中构造一个新的类型。从某种意义上说,它们是类型级别上的函数。

现在,根据我们的类比:你所问的问题的类比是什么?好吧,它是这样的:"值构造函数(即函数)可以被认为是函数式编程语言中的值吗?">

答案是:这取决于编程语言。现在,对于函数式编程语言,几乎所有(如果不是全部的话)的答案都是"是"。这取决于你对"函数编程语言"的定义。有些人将函数编程语言定义为以函数为值的编程语言,所以根据定义,答案通常是"是"。但是,有些人将函数式编程语言定义为不允许副作用的编程语言,在这种语言中,函数不一定是值。

最著名的例子可能是约翰·巴克斯的FP,来自他的开创性论文《编程可以从冯·诺依曼风格中解放出来吗?》?–程序的函数样式及其代数。在FP中,有一个"类函数"事物的层次结构。函数只能处理值,函数本身不是值。然而,有一个"泛函"的概念,它是"函数构造函数",即它们可以将函数(以及值)作为输入和/或将函数作为输出产生,但不能将泛函作为输入和(或)将其作为输出产生。

因此,FP可以说是一种函数式编程语言,但它没有函数作为值。

注:作为值的函数也称为"一阶函数",将函数作为输入或将其作为输出返回的函数称为"高阶函数"。

如果我们看一些类型:

1   :: Int
[1] :: List Int
add :: Int → Int
map :: (a → b, List a) → b

你可以看到,我们可以很容易地说:任何类型中有箭头的值都是函数。任何类型中有多个箭头的值都是高阶函数。

同样,这也适用于类型构造函数,因为除了在类型级别上,它们实际上是一样的。在一些语言中,类型构造函数可以是类型,而在某些语言中则不能。例如,在Java和C中♯,类型构造函数不是类型。C中不能有List<List>♯,例如您可以在Java中写下类型List<List>,但这是误导性的,因为两个List的含义不同:第一个List是类型构造函数,第二个List原始类型,所以这实际上不是使用类型构造函数作为类型。

与上面的类型示例等效的是什么?

Int     :: Type
List    :: Type ⇒ Type
→       :: (Type, Type) ⇒ Type
Functor :: (Type ⇒ Type) ⇒ Type

(注意,我们怎么总是有Type?事实上,我们只处理类型,所以我们通常不写Type,而是简单地写*,发音为"Type"):

Int     :: *
List    :: * ⇒ *
→       :: (*, *) ⇒ *
Functor :: (* ⇒ *) ⇒ *

因此,Int是一个适当的类型,List是一个接受一个类型并生成一个类型的类型构造函数,(函数类型构造函数)接受两个类型并返回一个类型(假设仅使用一元函数,例如使用currying或传递元组),而Functor是一个类型构造函数,它本身接受一个型型构造函数并返回一种类型。

这些"类型"被称为种类。与函数一样,任何带有箭头的东西都是类型构造函数,任何带有多个箭头的东西是更高级的kinded类型构造函数

与函数一样,有些语言允许更高级的类型构造函数,有些则不允许。您在问题中提到的两种语言Scala和Haskelldo,但如上所述,Java和C♯不要。

然而,当我们看你的问题时,有一个复杂的问题:

那么,类型构造函数也是类型吗?

不是,不是。至少我不懂任何语言。请看,虽然您可以拥有以类型构造函数为输入和/或将其作为输出返回的更高级的kinded类型构造函数,但您不能拥有以类型构造器为类型的表达式、值、变量或参数。不能有接受List或返回List的函数。不能有Monad类型的变量。但是,可以具有类型为Int的变量。

因此,很明显,类型和类型构造函数之间是有区别的。

好吧,类型和类型构造函数都有自己的演算,它们都有种类。例如,如果你在ghci中使用:k (Maybe Int),你会得到*,现在这是一个合适的类型,它(通常)有居民。在这种情况下,NothingJust 42*现在具有更具描述性的别名Type

现在,您可以查看构造函数的类型,即Maybe:k Maybe将为您提供* -> *。有了别名,这就是您所期望的Type -> Type。它采用Type构造Type。现在,如果您将类型视为一组值,那么一个好问题是Maybe具有哪组值?没有,因为它不是真正的类型。您可能会尝试类似Just的东西,但它的类型是a -> Maybe aType,而不是MaybeType -> Type

至少在Haskell中,有一个层次结构可以大致描述如下。

术语是运行时存在的东西,例如1'a'(+)等值。

每个术语都有一个类型,如IntCharInt -> Int -> Int

每个类型都有一个类型,所有类型都有相同的类型,即*

然而,像[]这样的类型构造函数具有* -> *类,因此它不是类型。相反,它是从类型到类型的映射


还有其他类型,包括(除了** -> *,每个都有一个例子):

  • * -> * -> *(Either)
  • (* -> *) -> * -> *(ReaderT,单端变压器)
  • Constraint(Num Int)
  • * -> Constraint(Num;这是一种类型类)

最新更新