我定义了以下数据类型:
type MySet a = (a -> Bool)
我想用它来定义一组具有以下属性的函数: 对于func3中的所有f,f 3 == 2.
func3 :: MySet (Eq a => a -> a)
func3 = (\x -> (x 3) == 2)
出现以下错误:
Illegal polymorphic or qualified type: Eq a => a -> a
Perhaps you intended to use -XLiberalTypeSynonyms
In the type signature for `func3': func3 :: MySet (Eq a => a -> a)
如果我不使用Eq类型类,我会收到此错误:
No instance for (Eq a) arising from a use of `=='
Possible fix:
add (Eq a) to the context of
the type signature for func3 :: MySet (a -> a)
答案 0 :(得分:5)
通常,解决涉及类型同义词(看起来像type ... = ...
的问题)的问题的第一步是通过手动替换同义词(type
表达式的左侧)来实现扩张(右手边)。所以:
func3 :: MySet (Eq a => a -> a)
变为:
func4 :: (Eq a => a -> a) -> Bool
现在GHC给了我们一个更有帮助的错误:
Illegal polymorphic or qualified type: Eq a => a -> a
Perhaps you intended to use RankNTypes or Rank2Types
In an expression type signature: (Eq a => a -> a) -> Bool
RankNTypes
是一个有趣的扩展,但在这里不是很有用。 (我稍后会解释)。
早上好指出,您可能想要做的只是将约束移出括号:
func5 :: Eq a => (a -> a) -> Bool
然后GHC让您知道您还需要Num
。除此之外,我们有一个看起来很普通的类型签名:=>
之前的约束,然后是常规类型变量和特定类型。这很好;我们通常希望类型尽可能简单(但不是更多)。
但是让我们备份并检查两件事:输入同义词和RankNTypes
。
首先,您将MySet
称为“数据类型”。想到它,这是一种危险的方式。它实际上是一个类型的同义词,这意味着它的含义:MySet (a -> a)
和(a -> a) -> Bool
实际上是同义词;他们的意思是一样的。对比data MySetD a = MySetD (a -> Bool)
之类的东西。在那里,MySetD
实际上是一种诚实的上帝数据类型,不能被替换为wil-nilly,(a -> Bool)
,反之亦然。
第二:RankNTypes
有什么用?如果我们打开该扩展程序,我们可以写下:
funcRN :: (forall a. (Eq a, Num a) => a -> a) -> Bool
funcRN = (\x -> (x 3) == 2)
它可以用funcRN ((+) 1)
之类的东西做你想做的事。但是这个呢?
g :: Int -> Int
g x = x - 1
funcRN g
这不起作用。 funcRN
需要一个可以使用任何类型a
的函数作为其参数,以便a
是Eq
和Num
的实例。这就是forall a. (Eq a, Num a) =>
位意味着什么。由于g
仅适用于一个类型Int
,因此funcRN
的类型签名是不可接受的。