some and many fail to converge
andersk opened this issue · comments
The default definitions of some
and many
fail to converge for Stream
.
λ> toList (many (return 1 <|> return 2) :: Stream [Int])
It’s possible to come up with definitions of some
and many
that work better than the default ones:
some v = (:) <$> suspended v <*> many v
many v = suspended (some v) <|> pure []
λ> toList (many (return 1 <|> return 2) :: Stream [Int])
[[],[1],[2],[1,1],[2,1],[1,2],[2,2],[1,1,1],[2,1,1],[1,2,1],[2,2,1],[1,1,2],[2,1,2],[1,2,2],[2,2,2],[1,1,1,1],[2,1,1,1],[1,2,1,1],[2,2,1,1],[1,1,2,1],[2,1,2,1],[1,2,2,1],[2,2,2,1],[1,1,1,2],[2,1,1,2],[1,2,1,2],[2,2,1,2],[1,1,2,2],[2,1,2,2],[1,2,2,2],[2,2,2,2],[1,1,1,1,1],…
Though perhaps this indicates a deeper problem with the existing definitions of <$>
, <*>
, and <|>
?
It's also possible to do it without the suspensions:
-- converges
some v = (:) <$> v <*> many v
many v = pure [] <|> some v
And it's possible to reintroduce the original issue by adding a suspension:
-- diverges
some v = (:) <$> v <*> many v
many v = suspended (pure []) <|> some v
This is an issue with left recursion generally, see the note in Oleg's original code:
-- The following code is not in general MonadPlus: it uses Incomplete
-- explicitly. But it supports left recursion! Note that in OCaml, for example,
-- we _must_ include that Incomplete data constructor to make
-- the recursive definition well-formed.
-- The code does *not* get stuck in the generation of primitive tuples
-- like (0,1,1), (0,2,2), (0,3,3) etc.
pythagorean_triples' =
let number = (Incomplete number >>= return . succ) `mplus` return 0
I think miniKanren addresses it by liberally adding suspensions (delay/incomplete) everywhere in the higher-level abstractions...