如果我想在C ++中创建一个新类型,我会在其中重载一堆运算符,我可以这样做:
class Stringy {
public:
explict Stringy(const char *buffer){}
friend Stringy operator + (const Stringy &s1, const Stringy &s2) { ... }
friend Stringy operator - (const Stringy &s1, const Stringy &s2) { ... }
friend std::ostream& operator << (std::ostream &oss, const String& s1) { ... }
};
现在如果我试图在Haskell中做同样的事情,我发现自己在做(一个例子):
data Stringy = Stringy([Char])
-- do something unrelated here --
(+) :: Stringy -> Stringy -> Stringy
(-) :: Stringy -> Stringy -> Stringy
(removeDups) :: Stringy -> Stringy
-- do something else unrelated here --
(>>) :: Stringy -> IO --(is IO right?)
我的观点是c ++看起来更加放在一起,因为你在该类中所做的一切都以某种方式与类相关。另一方面,haskell one的操作员声明可能遍布整个地方而不需要在一起。如果有人看一下c ++代码,他们可以立即识别哪些操作是类的一部分而哪些不是。我如何在Haskell中实现同样的一致性?
我仍然是Haskell的初学者,所以请使用简单的做事方式。感谢
答案 0 :(得分:1)
正如丹尼尔所说,优秀的图书馆设计师确实试图将相关功能放入同一个模块中。通常情况下,类型Stringy
以及Stringy
上的所有“基本”操作都位于模块Stringy
(或X.Y.Z.Stringy
)中,文件{{1 }}
最终,我认为您会欣赏Haskell为您提供的灵活性。 例如,假设您要定义类型为
的函数Stringy.hs
这不适用于三个类型类中的任何一个(myfunction :: Stringy -> Thingy -> Doohicky
,Stringy
或Thingy
),因为它引用的类型不属于类型类。
也许这三个类型分为三个单独的模块,很久以前由不同的人编写。
你是第一个意识到Doohicky
将是一个有用的操作的人。
Haskell允许您将此功能放在您认为最有意义的地方。
您可以创建一个全新的模块,专门用于从其他类型类的值组合生成myFunction
的方法。