The basic rule-of-thumb is that in FP programming functions do the same job as objects do in OO-programming. You can call their methods (well, the "call" method anyway) and they respond acording to some encapsulated, internal rules. In particular, every decent FP language out there lets you have "instance variables" in your function with closures / lexical scoping.
var make_OO_style_counter = function(){
return {
counter: 0
increment: function(){
this.counter += 1
return this.counter;
}
}
};
var make_FP_style_counter = function(){
var counter = 0;
return fucntion(){
counter += 1
return counter;
}
};
Now the next question is what do you mean by an interface? One approach is using nominal interfaces (it conforms to the interface if it says it does so) - this one usually depends a lot on what language you are using so lets leave it for latter. The other way to define an interface is the structural way, seeing what parameters thing receive and return. This is the sort of interface you tend to see in dynamic, duck-typed languages and it fits very well with all of FP: an interface is just the types of the input parameters to our functions and the types they return so All functions matching the correct types fit the interface!
Therefore, the most straightforward way of representing an object matching an interface is to simply have a group of functions. You usually get around the uglyness of passing the functions separately by packing them in some sort of record:
var my_blarfable = {
get_name: function(){ ... },
set_name: function(){ ... },
get_id: function(){ ... }
}
do_something(my_blarfable)
Using naked functions or records of functions will go a long way in solving most of your common problems in a "fat-free" manner without tons of boilerplate. If you need something more advanced than that, sometimes languages give you extra features. One example people mentioned is Haskell type classes. Type classes essentially associate a type with one of those records of functions and lets you write things so the dictionaries are implicit and get automatically passed to inner functions as appropriate.
-- Explicit dictionary version
-- no setters because haskell doesn't like mutable state.
data BlargDict = BlargDict {
blarg_name :: String,
blarg_id :: Integer
}
do_something :: BlargDict -> IO()
do_something blarg_dict = do
print (blarg_name blarg_dict)
print (blarg_id blarg_dict)
-- Typeclass version
class Blargable a where
blag_name :: a -> String
blag_id :: a -> String
do_something :: Blargable a => a -> IO
do_something blarg = do
print (blarg_name blarg)
print (blarg_id blarg)
One important thing to note about typeclasses however is that the dictionaries are associated with the types, and not with the values (like what happens in the dictionary and OO versions). This means you that the type system doesn't let you mix "types" [1]. If you want a list of "blargables" or a binary function taking to blargables then typeclasses will constrain everything to be the same type while the dictionary approach will let you have blargables of different origins (which version is better depends a lot in what you are doing)
[1] There are advanced ways to do "existential types" but its usually not worth the trouble.