它是否支持声明和实现的分离(Java中的接口和类)等概念?
如何限制访问(如Java中的访问修饰符)?
答案 0 :(得分:55)
如何在Haskell中分离声明和实现?
在Haskell中你可以定义一个typeclass,它与面向对象的类有很大不同,所以不要让这个名字欺骗你。使用关键字class
,您可以声明函数名称和类型签名,可以在其他地方为特定数据类型实例化(实现)。
例如,Hashable类型类定义了hash
函数,它可以将任何实例化的数据类型转换为Int
。有一个新的,时髦的数据类型,你希望能够哈希?很好,做一个Hashable的例子。最常见的数据类型由定义Hashable
的模块实例化(请参阅“实例”的链接文档)。
类型类不是定义接口的唯一方法。经常被低估的方法是普通的旧数据结构。因为Haskell具有第一类函数,所以您可以定义一个具有字段函数的数据结构:
data ShuttleInterface =
SI { launch :: Delay -> IO Handle
, deploy :: Payload -> IO ()
, getStatus :: IO Status
}
您的函数可以构建或使用此数据结构:
deployAllSensors :: ShuttleInterface -> IO ()
deployAllSensors shuttle = do
status <- getStatus shuttle
let notDeployed = filter (not . deployed) (sensors status)
when (isOrbiting status) (mapM_ deploySensor notDeployed)
-- we used the well-known Haskell functions: filter, not, , when, mapM_
-- and some supporting functions were assumed:
isOrbitting :: Status -> Bool
deploySensor :: Sensor -> IO ()
sensors :: Status -> [Sensor]
deployed :: Sensor -> Bool
如何限制对Haskell中数据的访问?
为了提供抽象,Haskell使用Algebraic Data Types。为了保护字段,开发人员声明了一种数据类型,但是没有导出它的构造函数 - 相反,它们只导出一组维护所需不变量的安全基元。
例如,Map模块提供了一个平衡树。如果任何人只能使用Branch
和Leaf
的原语来声明地图,则无法保证平衡,因此制造商不会将其导出。构建映射必须依赖于从Data.Map导出的内容(以及那些可以通过在同一模块中访问/使用构造函数的内容),例如fromList
,empty
,{{1和一大堆修饰符。
答案 1 :(得分:20)
请参阅Oleg Kiselyov和Ralf Laemmel的Haskell's Overlooked Object System,详细解释如何在Haskell中实现OO概念。但正如Antal在评论中所说,不要试图在Haskell中编写Java程序。
请记住,对象是一个穷人的封闭,封闭是一个穷人的对象。
答案 2 :(得分:5)
类型类确实是在OO概念上远程提醒的唯一构造 - 在这种情况下,在接口上。但是,与java不同,类型类不是类型。
关于类型类的一个好处是我可以创建一个完全不相关的,已经存在的类型类的成员。而在java中,有时人们会认为:这些来自包org.a的类A和来自com.b的B我应该使用的应该是第三个包实现接口Y,但没有办法做到不需要许多样板代码,附加间接,编组等。
BTW,作为一名老年程序员,我想指出“声明和实施的分离”本身与OOP无关。仅仅因为大多数OO-languga支持它并不意味着在OO发明之前这个概念在很长一段时间内并不为人所知。感兴趣的年轻人如果认为在OO主流化之前编程必须处于“石器时代”水平,可能会查找MODULA,例如,声明和实施的分离不仅是可能的,而且是由语言强制执行的。答案 3 :(得分:2)
值得一提的是lenses。它们允许你写出a.b.c.d.e
&#34;表达式#34;以一种可以组合的方式。
可以为每个数据结构定义.
。所以在某种意义上,.
是Haskell的一等公民。它可以命名,存储,两个.
- s可以组成,等等。
答案 4 :(得分:0)
我只是偶然发现了某事,请参阅https://github.com/complyue/ooh,以了解具有完整机器的可运行程序(尽管完整代码仍然非常短)。
我从没想过 OO 时尚的程序可以用 Haskel 编写 如此直截了当!
构造对象:
!o <- classC $^ (777, "hahah")
调用直接方法:
cx0 <- o $. getNumC $ ()
o $. setNumC $ 888
调用基本方法:
bx0 <- (o $.. cast'C'as'B) getNumB ()
(o $.. cast'C'as'B) setNumB 999
方法参数必须像这里原型那样未使用,我想它是 不过,在编写 OO 样式代码时会具有更好的风味。
虽然目前看来手工制作的对象类定义很冗长, 我相信 Template Haskell 可以提供很多更好的语法糖。