Earlier quoted context omitted.
This analogy misses something fundamental. See how the assignments to x and y are of very different character than the predicate? Notice the return path (`else []`). `amb` doesn't need this. `amb` merges the assignments and predicate - this is important because you may not know your argument count statically, i.e. if your arguments are a list. But beyond that, `amb` may backtrack an arbitrarily deep call stack, so th…
We can implement it with a single `amb` function, too (I took some shortcuts that might have hidden some of the nature of the implementation)! -- Lifts a list into Amb. amb :: [a] -> Amb a If we assume Amb is just List, then: amb = id If we write the example in the original article in desugared style, we get: amb [1, 2, 3] >>= \x -> amb [4, 5, 6] >>= \y -> if x * y /= 8 then amb [] else pure () >> pure (x, y) (we are…
The Haskell version requires each callee to be annotated with the `Amb` return type. It cannot be used to escape unless the caller is prepared for it to escape. That's a significant limitation (but all we're really saying is that Haskell doesn't support call/cc).