This solution uses dependent types (and may be too heavy, check if dfeuer answer is enough for your needs).
The solution uses the GHC.TypeLits module from the database, as well as the typelits-witnesses package.
Here is a difference function that takes two integer arguments (known statically) and complains at compile time when the first number is greater than the second:
{-# language TypeFamilies #-} {-# language TypeOperators #-} {-# language DataKinds #-} {-# language ScopedTypeVariables #-} import GHC.TypeLits import GHC.TypeLits.Compare import Data.Type.Equality import Data.Proxy import Control.Applicative difference :: forall n m. (KnownNat n,KnownNat m,n <= m) => Proxy n -> Proxy m -> Integer difference pn pm = natVal pm - natVal pn
We can check this from GHCi:
ghci> import Data.Proxy ghci> :set -XTypeApplications ghci> :set -XDataKinds ghci> difference (Proxy @2) (Proxy @7) 5 ghci> difference (Proxy @7) (Proxy @2) ** TYPE ERROR **
But what if we want to use a function with values ββdefined at runtime? Say the values ββwe read from the console or from a file?
main :: IO () main = do case (,) <$> someNatVal 2 <*> someNatVal 7 of Just (SomeNat proxyn,SomeNat proxym) -> case isLE proxyn proxym of Just Refl -> print $ difference proxyn proxym Nothing -> error "first number not less or equal" Nothing -> error "could not bring KnownNat into scope"
In this case, we use functions such as someNatVal and isLE . These functions may fail with Nothing . However, if they succeed, they return a value that "testifies" to some kind of limitation. And by comparing the patterns with the witness, we bring this restriction into scope (this works because the witness is GADT).
In this example, pattern matching Just (SomeNat proxyn,SomeNat proxym) brings KnownNat constraints for the two arguments to the scope. And matching the Just Refl brings the n <= m constraint into scope. Only then can we call our function difference .
So, in a sense, we have shifted all efforts so that the arguments satisfy the required preconditions from the function itself.