2016-09-16 13 views
0

警告:非常初学者的问题。如何理解Haskell类型构造函数的有效输入集?

我目前深陷在Haskell的书我读代数类型的部分,我已经遇到了下面的例子:

data Id a = 
    MkId a deriving (Eq, Show) 

idInt :: Id Integer 
idInt = MkId 10 

idIdentity :: Id (a -> a) 
idIdentity = MkId $ \x -> x 

OK,坚持住。我不完全了解idIdentity示例。书中的解释是:

这有点奇怪。类型Id接受参数,数据 构造函数MkId接受相应多态的 类型的参数。因此,为了获得Id Integer类型的值,我们需要 将a -> Id a应用于Integer值。这将a类型变量绑定到 Integer,并在类型构造函数中使用(->),给我们 Id Integer。我们还可以通过将a绑定到 类型和术语级别中的多态函数来构建MkId值,该值是身份 函数。

但是等等。为什么只有完全多态的功能?我以前的理解是,a可以是任何类型。但很显然,受限的多态类型不起作用:(Num a) => a -> a不会在这里工作,并且GHC错误表明,只有完全态类型或“合格类型”(不知道那些是什么)是有效的:

f :: (Num a) => a -> a 
f = undefined 

idConsPoly :: Id (Num a) => a -> a 
idConsPoly = MkId undefined 

Illegal polymorphic or qualified type: Num a => a -> a 
Perhaps you intended to use ImpredicativeTypes 
In the type signature for ‘idIdentity’: 
    idIdentity :: Id (Num a => a -> a) 

编辑:我是一个笨蛋。我在下面的答案中写下了类型签名,正如@chepner在他的回答中指出的那样。这也解决了我在下面的下一句话中的困惑......

回想起来,这种行为是有道理的,因为我还没有为Id定义Num实例。但那么什么解释我能​​够在idInt :: Id Integer中应用Integer这种类型?

所以在一般情况下,我想我的问题是:什么是特定的类型构造函数的有效输入集合?只有完全多态类型?那么什么是“合格类型”呢?等...

+0

限定类型是指具有上下文的那些类型,即以'Constraint => ...'开始。约束是“资格”。 –

+0

进入限定类型和多态的一个好的开端是这篇关于排名n类型的博客文章https://ocharles.org.uk/blog/guest-posts/2014-12-18-rank-n-types.html – epsilonhalbe

回答

3

你只是在错误的地方的类型构造函数。以下是罚款:

idConsPoly :: Num a => Id (a -> a) 
idConsPoly = MkId undefined 

类型构造Id在这里有一种* -> *,这意味着你可以给它具有一种*(包括所有“普通”的类型)的任何值,并返回一个新值种类*。一般来说,你更关心箭头函数(?),其中的类型构造函数只是一个例子。

TypeProd是三元类型构造器,其头两个参数有样* -> *

-- Based on :*: from Control.Compose 
newtype TypeProd f g a = Prod { unProd :: (f a, g a) } 

Either Int是其值具有一种* -> *但不是类型构造,作为类型构造Either的局部应用的表达到无限型构造函数Int

+0

Ahhhhhhhh 。那是一个愚蠢的错误。我很抱歉。谢谢。所以基本上,类型构造函数的域是所有可能类型的集合,然后呢? – gogurt

+0

或多或少。有些类型的细微差别我确信我不完全理解,但是https://wiki.haskell.org/Kind将普通类型定义为具有'*'种类,并将类型构造函数定义为具有'P - > Q'类型其中'P'和'Q'是种类。 (这里额外的一般性允许'( - >)'有'* - > * - > *',其中'P'和'Q'分别是'*'和'* - > *'。) – chepner

+2

@ chepner次要术语修正:“类型构造函数”是一个技术术语,与具有一种形式'P - > Q'的属性正交。例如,'Int'是类型'*'的类型构造函数,'Either Int'具有箭头类型,但不是类型构造函数。通过类比术语构造函数:'False'是没有箭头类型的构造函数,而'(+)0'在其类型中有一个箭头,但不是构造函数。 –

0

类型签名几乎是正确

idConsPoly :: (Num a) => Id (a -> a) 

应该是正确的,但我有我的手机上没有GHC来进行测试。 此外,我认为你的问题是相当广泛的,因此我故意只回答这里的具体问题。

1

也有助于你的困惑是你误解了来自GHC的错误信息。这意味着“Num a => a -> a是多态或限定类型,因此是非法的(在这种情况下)”。

你从书中引用的最后一句话措辞不是很好,也可能是导致误解。意识到在Id (a -> a)中参数a -> a而不是是一个多态类型,但只是碰巧提到类型变量的普通类型很重要。多态的东西是idIdentity,对于任何类型a可以有Id (a -> a)类型。

在标准Haskell中,多态性和限定条件只能出现在类型签名类型的最外层。

+0

谢谢你。我想,我开始明白了。你碰巧知道另一个来源,我可以看看在第二段中更好地理解你的解释吗?我真的很想处理这个问题。 – gogurt

相关问题