Does Haskell support object oriented programming
See Haskell's Overlooked Object System by Oleg Kiselyov and Ralf Laemmel for a detailed explanation of how OO concepts can be implemented in Haskell. But as Antal said in the comments, don't try to write a Java program in Haskell.
Remember that objects are a poor man's closure, and closures are a poor man's object.
How do you separate declaration and implementation in Haskell?
In Haskell you can define a typeclass, which is rather different from an object oriented class so don't let the name fool you. Using the keyword class
, you can declare function names and type signatures which can be instantiated (implemented) elsewhere for a particular data type.
For example, the Hashable typeclass defines the hash
function, which can turn any instantiated data type into an Int
. Have a new, funky data type you want to be able to hash? Fine, make an instance of Hashable. The most common data types are instantiated by the module that defines Hashable
(see the linked documentation for 'Instances').
Typeclasses aren't the only way to define an interface. A method that is often under-rated is a plain old data structure. Because Haskell has first class functions, you can define a data structure that has functions as fields:
data ShuttleInterface =
SI { launch :: Delay -> IO Handle
, deploy :: Payload -> IO ()
, getStatus :: IO Status
}
And your functions can build or consume this data structure:
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
How do you restrict access to data in Haskell?
To provide abstraction, Haskell uses Algebraic Data Types. To protect fields developers declare a data type but don't export it's constructors - instead they only export a set of safe primitives that maintain desired invariants.
For example, the Map module provides a balanced tree. It couldn't guarantee balance if anyone could just declare a Map using the primitives of Branch
and Leaf
, so the makers didn't export those. Construction of a map must rely on what is exported from Data.Map (and those have access to/use the constructors by virtue of being in the same module) such as fromList
, empty
, singleton
, and a whole bunch of modifiers.
Type classes are indeed the only constructs that remind remotely on OO concepts - in this case, on interfaces. Though, unlike in java, type classes are not types.
One good thing about type classes is that I can make totally unrelated, already existing types members of a type class. Whereas in java, sometimes one thinks: These classes A from package org.a and B from com.b that I am using ought really be implementing interface Y from a third package, but there is no way to do it that would not require a lot of boilerplate code, additional indirections, marshalling etc.
BTW, as an elderly programmer I'd like to note that "separation of declaration and implementation" has per se nothing to do with OOP. Just because most OO-langugaes support it does not mean the concept was not well known for a long time before OO was invented. Interested youngsters who think that programming before mainstreaming of OO must have been on a "stone age" level may look up MODULA, for example, where separation of declaration and implementation is not only possible, but enforced by the language.