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

Document early termination of all and friends. #118

Open
milesfrain opened this issue Aug 20, 2020 · 2 comments
Open

Document early termination of all and friends. #118

milesfrain opened this issue Aug 20, 2020 · 2 comments
Labels
type: documentation Improvements or additions to documentation.

Comments

@milesfrain
Copy link
Contributor

milesfrain commented Aug 20, 2020

Do all, any, and, or terminate early (short-circuit) when encountering the first overpowering value (e.g. all can return false as soon it sees the first false).
If so, should we add a note to the docs?
If not, should we also add a note, explain why, and then point to other options to achieve this behavior?

@JordanMartinez
Copy link
Contributor

I believe Harry and I had a conversation about this once. I'll write what I remember from that conversation.

They do not short-circuit. If you look at the Haskell definition for Foldable, you will see that the elem function is included in the definition of Foldable whereas PureScript's elem is a derived function. So, why is PureScript different?

Haskell supports "default implementations" of type class members. Looking at the Haskell source code, we can see per the "MINIMAL" pragma that a data type only needs to implement either foldMap or foldr to have an instance for Foldable. All other functions defined in that class can be derived using one of those two functions. However, such defaults may not be as performant (i.e. short-circuit). Fortunately, these defaults can be overridden. So, if elem should short-circuit on a data type like List, someone writing an instance for List could stop the recursion as soon as the first element is found.

PureScript does not support default implementations. The closest thing we have are functions like foldrDefault that can be used within the definition of a type class member. Note: these need to be "eta-expanded" (i.e. include the arguments on the left hand side) to prevent a stack overflow issue.:

data List a = Cons a (List a) | Nil

instance foldableList :: Foldable List where
  foldMap aToMonoid list = -- normal definition
  foldr acc init list = foldrDefault (flip acc) init list

If PureScript did support default implementations, we could include things like all, any, or, etc. for free (as we already do via derived functions), but also get short-circuiting versions for types that can support that.

@hdgarrood
Copy link
Contributor

Yep 👍 There’s another factor in this, which is that it’s difficult to short circuit here because our versions of any, all, and, and or use a HeytingAlgebra constraint rather than a concrete Boolean type, which means that we can’t know whether we’ve seen a true or a false in order to short circuit unless we add an Eq constraint so that we can check for equality with either tt or ff (the generalised versions of true and false).

@JordanMartinez JordanMartinez added the type: documentation Improvements or additions to documentation. label Dec 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: documentation Improvements or additions to documentation.
Projects
None yet
Development

No branches or pull requests

3 participants