在Haskell中,“更高级的类型”*真的*类型?或者他们只是表示*具体*类型的集合而已,仅此而已?

时间:2016-05-22 00:05:45

标签: haskell types higher-kinded-types parametric-polymorphism

Paramametrically polymorphic functions

考虑以下功能:

f :: a -> Int
f x = (1 :: Int)

我们可能会说f的类型为a -> Int,因此f属于“多态”类型。

以下哪一项是考虑f的最准确方法?

  1. 实际上有一个类型为f a -> Int。但是,它可以用作f :: Int -> Intf :: Double -> Int等等。

  2. 从字面上讲,f的类型不是a -> Int。实际上,这只是一种简短的方式,表示存在函数f family ,其类型是具体的(即,有f :: Int -> Int,{{1} }等等;此外,这些功能中的每一个都彼此不同。)

  3. 更高的金属类型

    同样,我们可以考虑以下类型声明:

    f :: Double -> Double

    并且问两种观点中的哪一种更正确:

    1. 没有类型data Maybe a = Just a | Nothing ;事实上,只有一系列具体类型(MaybeMaybe Int等),仅此而已。

    2. 实际上 是一种类型Maybe String。这种类型是一种更高级的类型。当我们说它是一个“类型”时,我们的意思是字面意思(不是(1)的简写)。碰巧我们也可以编写MaybeMaybe Int等来生成不同的类型(这恰好是具体的)。但是,在一天结束时(即):Maybe DoubleMaybeMaybe Int表示三个不同的类型,其中两个是具体的,其中一个这是更高的。

    3. 问题摘要

      在Haskell中,“高级类型”真的有类型吗?或者只是具体类型“真实类型”,当我们谈到“更高级的类型”时,我们只是表示具体类型的家族。此外,paramametrically多态函数表示单一类型的函数,或者它们表示具体类型的集合函数(仅此而已)?

2 个答案:

答案 0 :(得分:9)

目前还不完全清楚你想要问什么,两种情况下1和2之间的实际区别是什么,但从基础数学的角度来看:

参数多态函数

f实际上有f :: forall a.a->int

类型

对于Haskell所基于的类型化lambda演算中的函数,它是完全合法的类型。它可以是:

f = λa:Type.λx:a.(body for f)

你如何从中获得Double->Int?您应用于Double类型:

f Double = (λa:Type.λx:a.(body for f)) Double => λx:Double.(body for f|a=Double)

Haskell在场景后面执行两种操作(类型抽象和类型应用程序),尽管可以使用forall GHC扩展明确声明类型签名中的XExplicitForAll部分,并明确地生成{{带有类型签名的Double->Int实例:

f

更高的金币类型

考虑一个简单的类型:

f_double :: Double -> Int
f_double = f

(是的,它是data Example = IntVal Int | NoVal )。

Maybe Int类型构造函数,就像Maybe数据构造函数一样。这是完全相同的事情,只有IntVal应用于Maybe的意义上只有一个级别更高级别,就像Type应用于{{1}一样}}

在lambda演算中,IntVal具有类型:

Int

Haskell不允许您从类型构造函数中获取类型,但允许您获取(这只是类型的奇特名称>):

Maybe

所以不,Maybe : Type->Type 不是类型:您不能拥有类型为:k Maybe Maybe :: * -> * 的对象。 Maybe(几乎)是从类型到类型的函数,例如Maybe是从值到值的函数。

我们将Maybe应用于IntVal的结果称为Maybe,就像我们将String应用于Maybe String作为IntVal一样}。

答案 1 :(得分:6)

首先提出一个问题:声明"所有列表的长度是否为"单个陈述或一系列陈述" list1有长度"," list2有长度",...?

如果您将f的类型设为明确forall,则会获得f :: forall a. a -> Int。首先,这不是更高级的"。我们可以在GHCI中执行以下操作:

λ> :set -XRankNTypes
λ> :k (forall a. a -> Int)
(forall a. a -> Int) :: *

所以f有一种*

现在,在Haskell中,我们可以使用~来表示类型相等。我们可以设置以下内容来检查GHCI中的内容:

λ> :set -XImpredicativeTypes
λ> :set -XTypeFamilies
λ> :t undefined :: ((~) Int Int) => a
undefined :: ((~) Int Int) => a :: a

这表明GHC为这个例子找出了类型相等。类型不等式将产生以下错误:

λ> undefined :: ((~) (Int -> Int) (Int)) => a

<interactive>:22:1:
    Couldn't match expected type ‘Int’ with actual type ‘Int -> Int’
    In the expression: undefined :: ((~) (Int -> Int) (Int)) => a
    In an equation for ‘it’:
    it = undefined :: ((~) (Int -> Int) (Int)) => a

现在直接使用此方法会阻止我们比较f的类型,但我发现了一个应该适用于我们目的的轻微变体:

λ> :t undefined :: forall a. ((a -> Int) ~ (Int -> Int)) => a
undefined :: forall a. ((a -> Int) ~ (Int -> Int)) => a :: Int

换句话说,如果f的类型等效于g :: Int -> Int,则a必须为Int。这类似于x = yy = 0所以x = 0。在我们指定x = 0之前,我们没有y = 0,直到那时我们才x = y

Maybe不同,因为它有以下类型:

λ> :k Maybe
Maybe :: * -> *

由于我们正在使用DataKinds,因此我们有:k (~) :: k -> k -> GHC.Prim.Constraint,因此我们可以执行以下操作:

λ> :t undefined :: (~) Maybe Maybe => Int
undefined :: (~) Maybe Maybe => Int :: Int

λ> :k Either ()
Either () :: * -> *

λ> :t undefined :: (~) Maybe (Either ()) => Int
Couldn't match expected type ‘Either ()’ with actual type ‘Maybe’

总而言之,f :: forall a. a -> Int与声明一样有意义,如果你给我任何东西,我会给你一个Int&#34;。你能否把这句话翻译成一堆陈述&#34;如果你给我一只狗......&#34;,&#34;如果你给我一分钱......&#34;?是的,但它削弱了声明。最后,准确地确定你的意思是什么&#34;相同&#34;你得到了答案。