arity :: Parameter -> Arity
arity ps = arity' (0,Just 0) ps
  where
    arity' x Empty = x
    arity' (a,_) (Asterisk _) = (a, Nothing)
    arity' (a, Just b) (Default _ _ x) = arity' (a,Just (b+1)) x
    arity' (a, Just b) (P _ x) = arity' (a+1, Just (b+1)) x
    arity' (a, Just b) (Pattern _ _ x) = arity' (a+1, Just (b+1)) x
    arity' x (Alternatives []) = x
    arity'  _ (Alternatives ps) = (a', b')
      where
        ps' = map (arity' (0,Just 0)) ps
        a' = minimum $ map fst ps'
        b' = foldl max' (Just 0) (map snd ps')
        max' Nothing _ = Nothing -- Nothing represents no limit (i.e. infinity) so it is the maximal value
        max' _ Nothing = Nothing
        max' (Just a) (Just b) = Just (max a b)
    arity' a (Guard _ x) = arity' a x

-- | Will n parameters match the given Arity
arity :: Parameter -> Arity
arity ps = arity' (0,Just 0) ps
  where
    arity' x Empty = x
    arity' (a,_) (Asterisk _) = (a, Nothing)
    arity' (a, Just b) (Default _ _ x) = arity' (a,Just (b+1)) x
    arity' (a, Just b) (P _ x) = arity' (a+1, Just (b+1)) x
    arity' (a, Just b) (Pattern _ _ x) = arity' (a+1, Just (b+1)) x
    arity' x (Alternatives []) = x
    arity'  _ (Alternatives ps) = (a', b')
      where
        ps' = map (arity' (0,Just 0)) ps
        a' = minimum $ map fst ps'
        b' = foldl max' (Just 0) (map snd ps')
        max' Nothing _ = Nothing -- Nothing represents no limit (i.e. infinity) so it is the maximal value
        max' _ Nothing = Nothing
        max' (Just a) (Just b) = Just (max a b)
    arity' a (Guard _ x) = arity' a x

-- | Will n parameters match the given Arity
arity ps = arity' (0,Just 0) ps
  where
    arity' x Empty = x
    arity' (a,_) (Asterisk _) = (a, Nothing)
    arity' (a, Just b) (Default _ _ x) = arity' (a,Just (b+1)) x
    arity' (a, Just b) (P _ x) = arity' (a+1, Just (b+1)) x
    arity' (a, Just b) (Pattern _ _ x) = arity' (a+1, Just (b+1)) x
    arity' x (Alternatives []) = x
    arity'  _ (Alternatives ps) = (a', b')
      where
        ps' = map (arity' (0,Just 0)) ps
        a' = minimum $ map fst ps'
        b' = foldl max' (Just 0) (map snd ps')
        max' Nothing _ = Nothing -- Nothing represents no limit (i.e. infinity) so it is the maximal value
        max' _ Nothing = Nothing
        max' (Just a) (Just b) = Just (max a b)
    arity' a (Guard _ x) = arity' a x

-- | Will n parameters match the given Arity