如果你要麻烦地限制这样的结果,你不妨让它的类型反映这一点。
data ZOT a = Zero | One a | Two a a
form :: a -> Maybe a -> ZOT a
form a Nothing = One a
form a (Just b) = Two a b
zeroOneOrTwo :: Alternative f => f a -> f (ZOT a)
zeroOneOrTwo a = (form <$> a <*> optional a) <|> pure Zero
如果您想要最多三个怎么办?还是最多四个?您可以通过几个语言扩展一次涵盖所有此类情况。
{-# LANGUAGE DataKinds, GADTs #-}
data Nat = Z | S Nat
data Natty n where
Zy :: Natty 'Z
Sy :: Natty n -> Natty ('S n)
data AtMost n a where
Nil :: AtMost n a
Cons :: a -> AtMost n a -> AtMost ('S n) a
atMost :: Alternative f => Natty n -> f a -> f (AtMost n a)
atMost Zy _ = pure Nil
atMost (Sy n) a = (Cons <$> a <*> atMost n a) <|> pure Nil
如果您不想使用任何花哨的扩展怎么办?好吧,它看起来不会那么漂亮,但如果你愿意,你仍然可以这样做,从 Ralf Hinze 的“Numerical Representations as Higher-Order Nested Datatypes”中获取一页。
data Z a = Z deriving (Show)
data S f a = Nil | Cons a (f a) deriving (Show)
class AtMost g where
atMost :: Alternative f => f a -> f (g a)
instance AtMost Z where
atMost _ = pure Z
instance AtMost g => (AtMost (S g)) where
atMost m = (Cons <$> m <*> atMost m) <|> pure Nil
请注意,现在有两种不同的方法来构造空结果,Z 和 Nil,具有不同的类型。当结果与请求一样大时使用Z,而当结果不足时使用Nil。
*AtMost> atMost (Just 3) :: Maybe ((S (S (S Z))) Int)
Just (Cons 3 (Cons 3 (Cons 3 Z)))
*AtMost> atMost Nothing :: Maybe ((S (S (S Z))) Int)
Just Nil
*AtMost> atMost undefined :: Maybe (Z Int)
Just Z