sebfisch / stream-monad

Simple, Fair and Terminating Backtracking Monad

Home Page:http://github.com/sebfisch/stream-monad

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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...