If you are faced with the problem of limiting such a result, you can make its type reflect this.
data ZOT a = Zero | One a | Two aa form :: a -> Maybe a -> ZOT a form a Nothing = One a form a (Just b) = Two ab zeroOneOrTwo :: Alternative f => fa -> f (ZOT a) zeroOneOrTwo a = (form <$> a <*> optional a) <|> pure Zero
What if you want up to three? Or until four? You can cover all such cases at once with several language extensions.
{-
What if you do not want to use any fancy extensions? Well, it will not look so pretty, but you can still do it if you want by taking the page from Ralph Hinze "Numerical representations as nested data types of higher orders".
data Z a = Z deriving (Show) data S fa = Nil | Cons a (fa) deriving (Show) class AtMost g where atMost :: Alternative f => fa -> f (ga) instance AtMost Z where atMost _ = pure Z instance AtMost g => (AtMost (S g)) where atMost m = (Cons <$> m <*> atMost m) <|> pure Nil
Note that there are now two different ways to construct an empty result, Z and Nil , with different types. Z used when the result is as large as the query, while Nil used when it ends short.
*AtMost> atMost (Just 3) :: Maybe ((S (S (SZ))) Int) Just (Cons 3 (Cons 3 (Cons 3 Z))) *AtMost> atMost Nothing :: Maybe ((S (S (SZ))) Int) Just Nil *AtMost> atMost undefined :: Maybe (Z Int) Just Z
source share