some
和 many
可以定义为:
some f = (:) <$> f <*> many f
many f = some f <|> pure []
也许看一下使用单子 do
语法如何编写 some
会有所帮助:
some f = do
x <- f
xs <- many f
return (x:xs)
所以,some f
执行 f
一次,然后“多次”运行,并将结果组合成列表。 many f
运行 f
“某些”次数,或者“另外”只返回空列表。其想法是它们都尽可能地运行 f
直到它“失败”,并将结果收集在列表中。区别在于,如果 f
失败,some f
将立即失败,而 many f
在这种情况下仍将成功并“返回”空列表。但所有这些的确切意义取决于如何定义 <|>
。
它只对解析有用吗?让我们看看它对基础实例 Maybe
、[]
和 STM
的影响。
首先看 Maybe
。 Nothing
表示失败,因此 some Nothing
也会失败并计算为 Nothing
,而 many Nothing
则成功并计算为 Just []
。 some (Just ())
和 many (Just ())
都永远不会返回,因为 Just ()
永远不会失败!在某种意义上,它们计算为 Just (repeat ())
。
对于列表,[]
表示失败,因此 some []
计算为 []
(没有答案),而 many []
计算为 [[]]
(有一个答案,即空列表)。同样,some [()]
和 many [()]
不会返回。扩展实例,some [()]
表示 fmap (():) (many [()])
,而 many [()]
表示 some [()] ++ [[]]
,因此您可以说 many [()]
与 tails (repeat ())
相同。
对于 STM
,失败意味着必须重试事务。因此,some retry
将重试自己,而 many retry
将简单地返回空列表。some f
和 many f
将反复运行 f
直到它重试。我不确定这是否有用,但我猜它不是。
所以,对于 Maybe
、[]
和 STM
,many
和 some
看起来并不是那么有用。它只在applicative具有某种状态使得多次运行相同内容时失败变得“越来越”可能的情况下才有用。对于解析器,这是与每个成功匹配相关联的缩小输入。
some (Just ())
等于 Just (repeat ())
有点误导人,即使加了 "在某种意义上" 的限定,因为这使我想知道像 some (Just ()) >>= return . head
这样的表达式是否会像 Just (repeat 1) >>= return . head
那样运行,但事实并非如此;后者终止而前者不会。 - Osep
,那么some p
是0个或多个X的解析器,而many p
是1个或多个X的解析器。 - Ingosome
和 many
是基于 <|>
实现的。这个组合器在其他方面也很有用。考虑 Either
: Just 0 <|> Just 1 = Just 0
, Nothing <|> Just 2 = Just 2
, Just 3 <|> Nothing = Just 3
, Nothing <|> Nothing = Nothing
。 - fuzAlternative
是否用于其他任何事情。你可以说,“一般来说”,当你想让某些东西运行多次(但不必须运行)时使用 some
,而使用 many
至少运行一次。 - ivanm