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

时间:2019-02-10 20:53:14

标签: scala haskell types type-theory

我正在使用Haskell编程语言,并且具有Scala和Java开发人员的背景。

我正在阅读类型构造函数背后的理论,但是我无法理解是否可以将它们视为类型。我的意思是,在Scala中,您使用关键字classtrait定义类型构造函数。考虑一下List[T]Option[T]。同样在Haskell中,您使用相同的关键字data,该关键字用于定义新类型。

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

3 个答案:

答案 0 :(得分:6)

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

现在,您可以查看Maybe的构造函数类型,:k Maybe将给您* -> *。使用别名,这就是您期望的Type -> Type。它需要Type构造一个Type。现在,如果您将类型视为一组值,那么一个好问题是Maybe拥有哪些值集?好吧,没有,因为它不是真正的类型。您可能会尝试使用类似Just的类型,但类型为a -> Maybe a的类型Type,而不是类型为Maybe的{​​{1}}。

答案 1 :(得分:6)

让我们看一个类比:函数。在某些数学分支中,函数称为值构造器,因为这就是它们的作用:您将一个或多个值放入其中,然后从中构造出新值。

除了在类型级别上,类型构造器是完全一样的:您将一个或多个类型放入其中,然后它们从中构造出一个新类型。从某种意义上说,它们是类型级别的功能。

现在,以我们的类比为例:您所提问题的类比是什么?嗯,是这样的:“可以在函数式编程语言中将值构造函数(即函数)视为值吗?”

答案是:它取决于编程语言。现在,对于函数式编程语言,几乎所有(如果不是全部)答案都是“是”。这取决于您对“功能编程语言”的定义。某些人将功能性编程语言定义为具有功能作为值的编程语言,因此根据定义,答案将是简单的“是”。但是,有些人将功能性编程语言定义为不允许产生副作用的编程语言,在这种语言中,功能不一定是值。

最著名的例子可能是约翰·巴库斯(John Backus)的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是一个类型构造函数,它本身接受一个类型构造函数并返回一个类型。

这些“类型-类型”称为种类。像函数一样,带有箭头的所有内容都是类型构造函数,带有多个箭头的所有内容都是类型较高的类型构造函数

和函数一样,某些语言允许使用类型较高的类型构造函数,而某些则不允许。您在问题中提到的两种语言Scala和Haskell 可以,但是如上所述,Java和C♯不会。

但是,当我们看到您的问题时,情况就复杂了

  

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

不是,不是。至少没有我知道的任何语言。看到,尽管您可以拥有类型较高的类型构造函数,这些类型构造函数将类型构造函数作为输入和/或将它们作为输出返回,但是您不能具有以类型构造函数作为其类型的表达式或值,变量或参数。您不能有接受List或返回List的函数。您不能具有类型Monad的变量。但是,您可以具有类型为Int的变量。

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

答案 2 :(得分:3)

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

术语是在运行时存在的事物,例如1'a'(+)之类的值。

每个词都有一个类型,例如IntCharInt -> Int -> Int

每种类型都有种类,并且所有类型都具有相同的种类,即*

尽管像[]这样的类型构造函数具有种类* -> *,所以它不是类型。相反,它是从类型到类型的映射


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

  • * -> * -> *Either
  • (* -> *) -> * -> *ReaderT,monad转换器)
  • ConstraintNum Int
  • * -> ConstraintNum;这是类型类的一种)
相关问题