Search code examples
haskellclojurefunctional-programminginvariants

Managing invariants in Clojure / Haskell


I have been comparing OOP and FP methodologies and I could not put my head around one thing in functional programming - keeping invariants in the data structure.

For example imagine the following requirements.

We have a list of projects and every project a has list of tasks and a list of assigned members. Every task can have a worker assigned to it but only from the list of project assigned members.

I can imagine how I can solve this problem in a OOP language, for example in Java, by adding required checks and exceptions, and this would lead in my opinion to more robust code.

But as the data is separated from the behaviour in FP, how should I solve the same problem in FP, say in Clojure or Haskell?


Solution

  • Your question is very general, a lot of strategies could be used to solve related problems but, essentially, checking invariants (at runtime) is "equal" than in OOP

    assign :: Task -> Worker -> Either String Task
    assign task worker =
        if not (taskProject task) `containsWorker` worker
            then Left "You can't assign..."
            else Right $ task { taskWorkers = worker : taskWorkers task }
    

    One common behavior is hide data constructor (as Task, Worker and Project), the OOP counterpart is write private constructors.

    module Scheduler (
      Task   -- instead `Task (..)`
    , Worker -- instead `Worker (..)`
    ...
    , assign
    , createTask
    , createWorker
    ...
    ) where
    

    (I unkown the current Haskell support to friend, protected, ... counterpart probably not exists and you can find a lot of Haskell modules with Some.Module.Internals.Something with private objects)

    The main question is about how to structure the whole program to achieve the required behavior.

    Real World Haskell is a good starting point to learn about that or as suggested on related question Large-scale design in Haskell?

    On the other hand, about pre/post condition in Haskell you can read What are the options for precondition checking in Haskell.