警告:非常初学者的问题。
我目前陷入了Haskell书中关于代数类型的部分,我正在阅读,并且我遇到了以下示例:
data Id a =
MkId a deriving (Eq, Show)
idInt :: Id Integer
idInt = MkId 10
idIdentity :: Id (a -> a)
idIdentity = MkId $ \x -> x
好的,等一下。我不完全理解idIdentity
示例。书中的解释是:
这有点奇怪。类型
Id
接受参数和数据 构造函数MkId
接受相应多态的参数 类型。因此,为了获得Id Integer
类型的值,我们需要 将a -> Id a
应用于Integer
值。这会将a
类型变量绑定到Integer
并在类型构造函数中应用(->)
,给我们Id Integer
。我们还可以构造一个MkId
值作为标识 函数通过将a
绑定到两个类型中的多态函数 和术语水平。
但是等等。为什么只有完全多态函数?我之前的理解是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在下面的回答中指出的那样,我在下面写错了类型签名。这也解决了我在下面的句子中的困惑......
回想起来,这种行为是有道理的,因为我还没有为Num
定义Id
个实例。但是,是什么原因解释了我能够在Integer
中应用类似idInt :: Id Integer
的类型?
所以一般来说,我想我的问题是:类型构造函数的有效输入集是什么?只有完全多态的类型?什么是#34;合格类型"然后?等...
答案 0 :(得分: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
到nullary类型构造函数Int
的部分应用程序
答案 1 :(得分:1)
您的混淆也导致您误解了GHC的错误消息。这意味着“getLogger()
是一种多态或合格的类型,因此非法(在此上下文中)”。
你从这本书中引用的最后一句话措辞不是很好,也许可能导致了这种误解。重要的是要意识到在Num a => a -> a
中,参数Id (a -> a)
不是一个多态类型,而只是一个碰巧提到类型变量的普通类型。多态的是a -> a
,对于任何类型idIdentity
都可以有Id (a -> a)
类型。
在标准的Haskell多态中,限定只能出现在类型签名中类型的最外层。
答案 2 :(得分:0)
类型签名几乎是正确的
idConsPoly :: (Num a) => Id (a -> a)
应该是对的,虽然我手机上没有ghc来测试这个。 <子> 另外我认为你的问题相当广泛,因此我故意只回答这里的具体问题。 子>