Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

some and many fail to converge #5

Open
andersk opened this issue Nov 13, 2013 · 1 comment
Open

some and many fail to converge #5

andersk opened this issue Nov 13, 2013 · 1 comment

Comments

@andersk
Copy link

andersk commented Nov 13, 2013

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

@davidar
Copy link

davidar commented May 24, 2021

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants