How do I enforce run-time conditions on data in Haskell?

  • A+

I want to define a function f [Int] -> Int where f is equal to the sum of the elements in the list if the length of the list is a perfect square and is undefined otherwise. What is the idiomatic way to do this in Haskell?

In an imperative language I'd add a line to the effect of assert sqrt(len(xs)) is integer to generate an exception for the undefined cases. In a strongly-typed functional language like Haskell you want to build undefined conditions into the type system, however that can't be done here since there is no "list of length perfect square" type.

I'd prefer to have the program halt with an error in the undefined case rather than have the function return Nothing.


If you want to be formal about it it might be a good opportunity to use a smart constructor.

module PSqList     ( PSqList   -- constructor *not* exported     , fromList     ) where  newtype PSqList a = PSqList [a]     deriving (Functor, Foldable)  fromList :: [a] -> Maybe (PSqList a) fromList xs     | isPerfectSquare (length xs) = Just (PSqList xs)     | otherwise = Nothing 

Then when you use the PSqList module, you may only construct a PSqLists that have perfect square lengths.

It feels a bit strange to use a whole module for something like this; maybe you want a more general invariant-tracking system. This is a domain of a dependently typed language like Agda in general, but there is a lovely midpoint available in Haskell shown in the functional pearl Ghosts of Departed Proofs.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: