Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specifying invariants on value constructors

Consider the following

data Predicate = Pred Name Arity Arguments

type Name      = String
type Arity     = Int
type Arguments = [Entity]
type Entity    = String

This would allow the creation of

Pred "divides" 2 ["1", "2"]
Pred "between" 3 ["2", "1", "3"]

but also the "illegal"

Pred "divides" 2 ["1"]
Pred "between" 3 ["2", "3"]

"Illegal" because the arity does not match the length of the argument list.

Short of using a function like this

makePred :: Name -> Arity -> Arguments -> Maybe Predicate
makePred n a args | a == length args = Just (Pred n a args)
                  | otherwise = Nothing

and only exporting makePred from the Predicate module, is there a way to enforce the correctness of the value constructor?

like image 881
Nickolay Kolev Avatar asked Jan 26 '11 22:01

Nickolay Kolev


1 Answers

Well, the easy answer is to drop the arity from the smart constructor.

makePred :: Name -> Arguments -> Predicate
makePred name args = Pred name (length args) args

Then if you don't expose the Pred constructor from your module and force your clients to go through makePred, you know that they will always match, and you don't need that unsightly Maybe.

There is no direct way to enforce that invariant. That is, you won't be able to get makePred 2 ["a","b"] to typecheck but makePred 2 ["a","b","c"] not to. You need real dependent types for that.

There are places in the middle to convince haskell to enforce your invariants using advanced features (GADTs + phantom types), but after writing out a whole solution I realized that I didn't really address your question, and that such techniques are not really applicable to this problem in particular. They're usually more trouble than they are worth in general, too. I'd stick with the smart constructor.

I've written an in-depth description of the smart constructor idea. It turns out to be a pretty pleasant middle ground between type verification and runtime verification.

like image 175
luqui Avatar answered Nov 07 '22 06:11

luqui