Haskell:如何创建一个不允许,一个或两个Applicatives的函数?

时间:2016-09-25 19:18:32

标签: haskell applicative

Control.Applicative.optional允许处理零个或一个Applicatives。 很多&一些允许分别为0或更多,或1或更多。 我想创建一个处理零,一或两个的函数,具体来说。 签名可以是许多/一些,即

zeroOneOrTwo :: Alternative f => f a -> f [a]

我觉得这应该是非常简单的,但我已经玩了一段时间并且无法使其发挥作用。任何指针都将非常感激。

2 个答案:

答案 0 :(得分:8)

这个怎么样:

zeroOneOrTwo :: Alternative f => f a -> f [a]
zeroOneOrTwo a = go (2 :: Int)
  where
    go n
      | n > 0 = ((:) <$> a <*> go (n - 1)) <|> pure []
      | otherwise = pure []

答案 1 :(得分:5)

如果您遇到限制结果的麻烦,您也可以将其类型反映出来。

> ./lwt_socket_client 
_read
8
_read
0
totoche

如果您想要最多三个怎么办?或者最多四个?您可以使用几种语言扩展程序一次性涵盖所有此类案例。

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

如果您不想使用任何花哨的扩展,该怎么办?好吧,它看起来不那么漂亮,但如果你愿意,你仍然可以这样做,从Ralf Hinze的“数字表示作为高阶嵌套数据类型”中获取页面。

{-# 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

请注意,现在有两种不同的方法来构建具有不同类型的空结果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