我有这个任务,我必须在Haskell中定义2个类型类。一个很简单 - 它实现Ord并且有一个方法将给定类型转换为int。像这样:
class (Ord a) => Id a where
toInt :: a -> Int
但是我有另一个类型类 HasId ,它有一个方法 getId 。此方法应返回 Id 类型类。所以我写了这样的话:
class HasId a where
getId :: a -> Id a
我得到一个错误,我不知道如何解决。
• Expected kind ‘* -> Constraint’, but ‘Int’ has kind ‘*’
• In the class declaration for ‘HasId’
|
| class (Int a) => HasId a where | ^^^^^
• Expected a type, but ‘Id a’ has kind ‘Constraint’
• In the type signature: getId :: a -> Id a
In the class declaration for ‘HasId’
|
| getId :: a -> Id a |
有人可以告诉我如何在另一个类型类方法中返回类型类? 我应该首先实现 Id 类型类的一些实例吗?
答案 0 :(得分:7)
重要的是要理解Haskell class
与OO语言中的类非常不同。它是一个类型类,即它“将一组类型组合在一起”,而一个OO类将一组值组合在一起。 IOW,OO类是一个类型(包含值),但是Haskell类就像类型类型,就像它一样。
现在,函数/方法总是将值作为参数,并将值作为结果返回。但它不能给你一个类型,也不能给你一个“类型类的价值”,因为没有这样的东西。
相反,使用类型类的方法是:编写多态函数,即接受或产生某些未指定类型值的函数。这就是类型变量的用途。通常,多态签名意味着该函数可以处理任何类型的值,例如
length :: [a] -> Int
采用列表而不关心其元素的类型。但后来你说你关心使用了什么类型,即你要求他们在课堂上。这是一个约束,它是用=>
表示法编写的。 toInt
实际上有签名(由类声明自动生成)
toInt :: Id a => a -> Int
坦率地说,我怀疑这真的是你想要的。如果你只能使用Id a
将其转换为Int
,则效果的结果为Int
(只是带有类型注释,表示无论a
参数如何,此Id属于哪种对象。因此,您应该考虑使用 Id
类型 而不是Id
类。
newtype Id' a = Id {toInt :: Int} -- The prime ' symbol has no particular meaning,
-- I just use it for disambiguation.
然后,你有更明智的类型
toInt :: Id' a -> Int
不需要任何限制。
newtype
与OO类更相似,因为它实际上定义了一个具有可以传递的值的具体类型。
getId
方法也是一个约束多态函数,它可以采用“有Id
”的东西,并返回该Id。在这种情况下,一个类是有意义的(因为你可以有不同的数据结构,可以以不同的方式存储他们的ID)。现在这实际上是
class HasId a where
getId :: a -> Id' a
根据Welperooni's answer,使用原始的HasId
类来定义Id
确实也是可以转换的,只是它没有多大意义。 Id
是所有类型的类,可用作标识符。您可以表示getId
可以产生任何此类型的Id:
class HasId a where
getId :: Id b => a -> b
请注意,result-Id类型现在完全独立于要计算其Id的对象类型。 b
始终可以是任何 ID类型。正如我所说,这没有意义:为什么你需要很多代表Ids的不同类型,但需要所有HasId
类型来支持所有?
实际上这不能实现,因为没有机制允许你生成任意Id
类型的Id。这需要一个额外的方法
class Id a where
toInt :: a -> Int
fromInt :: Int -> a
现在你可以做到
class HasId a where
getId :: Id b => a -> b
data SomeObj { objName :: String
, objId :: Int }
instance HasId SomeObj where
getId (SomeObj _ i) = fromInt i
但是,如果您要求任何Id
类型都可以从Int
转换为Int
,那么这些类型必须与newtype Id' a
本身同构。因此,facility
方法几乎肯定更好。
答案 1 :(得分:1)
您将返回值声明为HKT Id a
,但您想要的是另一种类型,受类型类Id
约束。
您需要的不是getId :: a -> Id a
,而是getId :: Id b => a -> b