在我尝试调试的 Haskell 程序中,定义了一个类:
class Dictionary d where
lookupIn :: d -> Word -> String
我想创建一个名为的变量runs
并将其设为类型Dictionary
,以便我可以在 lookupIn 函数中使用它。但是,没有任何效果。我试过type runs = Dictionary
了,甚至data runs = Dictionary
但没有任何效果。
Haskell不是面向对象的语言。类型类不是类。变量不是“变量”(尽管这在这里无关紧要),当然也不是对象。
看到这个帖子。
PS我想这是家庭作业。尝试先学习这门语言(甚至一点点),Haskell 很可能比你想象的更有趣。
在 Haskell 中这是不可能的。在其他具有类型类结构的语言(Scala、Agda)中是可能的,但在 Haskell 中是不可能的。
可以在 Haskell 中创建一个类的实例:
instance Dictionary () where
lookupIn _ _ = "no"
然后使用它:
main = do
putStrLn $ lookupIn () "hello"
确实,实例的行为确实很像数据——它们在运行时由数据表示。这就是为什么在其他语言中您可以将实例存储在变量中,并显式地传递它们。
但是,在 Haskell 中,不可能命名一个实例,或者将它存储在一个变量中。也就是说,你不能这样做,或者类似的事情:
thisInstance :: Dictionary ()
thisInstance = ???
原因是在 Haskell 中,假设对于每个类型和类型类,只能有一个该类型类的实例应用于该类型。也就是说,您只能定义一个instance Dictionary ()
。由于只能有一个,因此命名没有意义。这对于 Haskell 的类型推断很方便——任何需要的实例都可以拉到当前函数的“参数”(真正的类型类约束)。
当然,也有可能实现相同的行为,只是不能使用类型类——记录对此很有效:
data DictionaryType d = DictionaryData { lookupIn :: d -> Word -> String }
现在lookupIn
有了 type DictionaryType d -> d -> Word -> String
,它是使用 typeclass 的 type 的字面翻译(Dictionary d) => d -> Word -> String
。你可以像这样使用它:
myDictionary :: DictionaryType ()
myDictionary = DictionaryData (\_ _ -> "no")
main = do
putStrLn $ lookupIn myDictionary () "hello"
在功能上与 typeclass 解决方案相同,唯一的区别是语法和类型检查的工作方式。
一种思考方式是:
在 OO 语言中,一个类定义了一个类型(即一组潜在值)和一组其他类型(即潜在的后代类)。
在 Haskell中,类型类只定义了一组类型(即类型类的潜在“实例”)。类型类本身不是类型。
(实际上我正在讨论集合论中集合和类之间的区别,这就是为什么它们被称为“typeclasses”而不是“typesets”。但这在这里并不重要。)