首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在Haskell中对类层次结构建模?

如何在Haskell中对类层次结构建模?
EN

Stack Overflow用户
提问于 2010-06-27 00:02:57
回答 4查看 2.6K关注 0票数 17

我是一名C#开发人员。从面向对象的角度出发,我首先从接口、类和类型层次结构的角度进行思考。由于Haskell缺乏面向对象,有时我发现自己被卡住了,我想不出一种方法来模拟Haskell的某些问题。

如何在Haskell中对涉及类层次结构的实际情况进行建模,如下所示:http://www.braindelay.com/danielbray/endangered-object-oriented-programming/isHierarchy-4.gif

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-06-27 00:39:19

让我们假设以下操作:人类可以说话,狗可以叫,一个物种的所有成员都可以与同一物种的成员交配,如果他们是异性的。我在haskell中是这样定义的:

代码语言:javascript
运行
复制
data Gender = Male | Female deriving Eq

class Species s where
    gender :: s -> Gender

-- Returns true if s1 and s2 can conceive offspring
matable :: Species a => a -> a -> Bool
matable s1 s2 = gender s1 /= gender s2

data Human = Man | Woman
data Canine = Dog | Bitch

instance Species Human where
    gender Man = Male
    gender Woman = Female

instance Species Canine where
    gender Dog = Male
    gender Bitch = Female

bark Dog = "woof"
bark Bitch = "wow"

speak Man s = "The man says " ++ s
speak Woman s = "The woman says " ++ s

现在,操作matable的类型为Species s => s -> s -> Boolbark的类型为Canine -> Stringspeak的类型为Human -> String -> String

我不知道这是否有帮助,但考虑到这个问题相当抽象的性质,这是我能想到的最好的办法。

编辑:回应Daniel的评论:

一个简单的集合层次结构可能如下所示(忽略已经存在的类,如Foldable和Functor):

代码语言:javascript
运行
复制
class Foldable f where
    fold :: (a -> b -> a) -> a -> f b -> a

class Foldable m => Collection m where
    cmap :: (a -> b) -> m a -> m b
    cfilter :: (a -> Bool) -> m a -> m a

class Indexable i where
    atIndex :: i a -> Int -> a

instance Foldable [] where
    fold = foldl

instance Collection [] where
    cmap = map
    cfilter = filter

instance Indexable [] where
    atIndex = (!!)

sumOfEvenElements :: (Integral a, Collection c) => c a -> a
sumOfEvenElements c = fold (+) 0 (cfilter even c)

现在,sumOfEvenElements接受任何类型的积分集合,并返回该集合中所有偶数元素的和。

票数 15
EN

Stack Overflow用户

发布于 2010-06-27 01:41:59

首先:标准的OO设计在Haskell中不能很好地工作。你可以与语言作斗争,并尝试制作类似的东西,但这将是一次挫折中的练习。所以第一步是寻找风格的解决方案,而不是寻找用Haskell编写OOP风格的解决方案的方法。

但这说起来容易做起来难!从哪里开始呢?

因此,让我们拆解一下OOP为我们做些什么的细节,并考虑一下这些细节在Haskell中可能是什么样子。

  • Objects:粗略地说,对象是一些数据和对这些数据进行操作的方法的组合。在Haskell中,数据通常是使用代数数据类型构造的;方法可以被认为是将对象数据作为初始隐式argument.
  • Encapsulation:的函数。然而,检查对象数据的能力通常仅限于它自己的方法。在Haskell中,有多种隐藏数据的方法,两个例子是:
    • 在一个单独的模块中定义数据类型,该模块不导出类型的构造函数。只有该模块中的函数才能检查或创建该类型的值。这在某种程度上可以与protectedinternal成员相比较。
    • 使用部分应用程序。假设函数map的参数发生了翻转。如果您将它应用于一组Int,您将得到一个(Int -> b) -> [b]类型的函数。在某种意义上,您给出的列表仍然“在那里”,但是除了通过函数之外,没有其他东西可以使用它。这可以与OOP成员相媲美,并且被部分应用的原始函数可以与OOP风格的constructor.

相媲美

  • "Ad-hoc“多态性:通常,在OO编程中,我们只关心某个东西实现了一个方法;当我们调用它时,所调用的特定方法是根据实际类型确定的。Haskell为编译时函数重载提供了类型类,这些类在许多方面比OOP languages.
  • Code reuse 中的类更灵活:老实说,我的观点是通过继承重用代码过去是错误的,现在也是错误的。我觉得像Ruby这样的混入是一种更好的面向对象解决方案。无论如何,在任何函数式语言中,标准方法都是使用高阶函数提取常见行为,然后专门化通用形式。这里的一个经典示例是fold函数,它概括了几乎所有的迭代循环、列表转换和线性递归functions.
  • Interfaces:根据您如何使用接口,有不同的选项:解耦实现的多态函数(
    • ):这里需要的是具有类型类约束的多态函数。例如,函数sort的类型为(Ord a) => [a] -> [a];它与您提供的类型的细节完全解耦,除非它必须是实现具有多个类型和共享接口的Ord.
    • Working的某个类型的列表:为此,您需要一个用于现有类型的语言扩展,或者为了简单起见,可以像上面那样在部分应用程序上使用一些变体--而不是您可以应用于它们的值和函数,而是提前应用函数并使用results.

  • Subtyping,原名" is -a“关系:这是你最不走运的地方。但是,从经验上讲,作为一名多年的专业C#开发人员,您确实需要子类型的情况并不常见。相反,请考虑以上内容,以及您尝试使用子类型relationship.

捕获的行为

您可能还会发现this blog post很有帮助;它快速总结了您将在Haskell中使用什么来解决一些标准设计模式在OOP中经常用于解决的问题。

作为最后的补充,作为一名C#程序员,您可能会发现研究它与Haskell之间的联系是很有趣的。相当多的负责C#的人也是Haskell程序员,最近C#中的一些新成员受到了Haskell的很大影响。最值得注意的可能是LINQ底层的一元结构,IEnumerable本质上是list monad。

票数 32
EN

Stack Overflow用户

发布于 2010-06-27 01:30:33

Haskell使用抽象数据类型,而不是类和对象。在构建和观察信息的组织方式问题上,这确实是两种兼容的观点。在这个问题上,我所知道的最好的帮助是威廉·库克的论文“Object-Oriented Programming Versus Abstract Data Types”。他有一些非常清楚的解释,大意是

  • 在基于类的系统中,代码是围绕构造抽象的不同方式进行组织的。通常,构造抽象的每种不同方式都被分配了自己的类。这些方法只知道如何观察结构的属性。
  • 在基于ADT的系统(如Haskell)中,代码是围绕着观察抽象的不同方式来组织的。通常,观察抽象的每种不同方式都被分配了自己的功能。该函数知道可以构造抽象的所有方法,并且它知道如何观察单个属性,而不是任何结构。

库克的论文将向你展示一个很好的抽象矩阵布局,并教你如何将任何类组织为ADY,反之亦然。

类层次结构还包含一个元素:通过继承重用实现。在Haskell中,这种重用是通过第一类函数实现的:Primate抽象中的函数是一个值,Human抽象的实现可以重用Primate抽象的任何函数,可以包装它们以修改其结果,等等。

在使用类层次结构的设计和使用抽象数据类型的设计之间没有一个完全合适的。如果您试图从一个音译到另一个音译,您将得到一些笨拙而不地道的东西-有点像用Java编写的FORTRAN程序。但是,如果您理解类层次结构的原则和抽象数据类型的原则,您就可以采用一种风格来解决问题,而在另一种风格中为同样的问题设计一个相当得体的解决方案。这确实需要练习。

附录:也可以使用Haskell的类型类系统来模拟类层次结构,但那是另一回事。类型类与普通类足够相似,以至于许多标准示例都可以工作,但它们又有很大的不同,可能会有一些非常大的意外和不匹配。虽然类型类对于Haskell程序员来说是一个无价的工具,但我建议任何学习Haskell的人学习使用抽象数据类型来设计程序。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3124511

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档