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

Add Alt, Plus and Alternative specs #197

Merged
merged 12 commits into from
Nov 4, 2016

Conversation

safareli
Copy link
Member

@safareli safareli commented Oct 27, 2016

Specs added:

  • Alt
  • Plus
  • Alternative
  • MonadZero
  • MonadOr
  • MonadPlus

TODO:

  • add laws in laws/*
  • update test
  • add mPlus and mOrElse ?

fixes #187

Monad{Zero,Or,Plus} are removed from this PR (reason)

the [Applicative](#applicative) and [Plus](#plus) specifications.

1. `x.ap(f.alt(g))` is equivalent to `x.ap(f).alt(x.ap(g))` (distributivity)
1. `M.pempty().ap(f)` is equivalent to `M.pempty()` (annihilation)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In purescript it's in different order and i think it's correct, so I have opened issue purescript-control#34

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of Applicative's interchange law they are equivalent so i have sticked to purescript's version

@safareli
Copy link
Member Author

safareli commented Oct 27, 2016

Also we can use zero instead of pempty (from semigroupoids.Plus)

If you like zero better than pempty 👍
if you don't like zero and prefer pempty 👎

make it consistant with purescript version, even tho they are equivalent because of Applicative's interchange law
@garyb
Copy link

garyb commented Oct 28, 2016

👍 for zero - we don't use that to avoid the mempty situation in PureScript only because it's used for yet another "zero" - that of Semiring 😄

@safareli
Copy link
Member Author

safareli commented Oct 28, 2016

Will change then! and if in future we add Semiring to FL, as it is subclass of Monoid than we would just use monoids empty for it.

@garyb
Copy link

garyb commented Oct 28, 2016

Well, this is a discussion for another day, but it's not really a subclass of Monoid as there are two possible Monoids for it: (+) and 0, and (*) and 1. We have Additive and Multiplicative newtypes for those Monoids for any Semiring... not sure what the JS answer to that would be!

- move patches and test structures into `internal`
  - `Compose` and patching of `Array` form `laws/traversable`
  - `equality`, `Sum` and patching of `String` form `id_test`
  - `Id` from `id`
- rename `id_test` to `test` as it's not just testing `Id` but `Maybe` and `Sum`
@rpominov
Copy link
Member

The PR LGTM overall 👍

Just: _ => this,
Nothing: () => b,
});
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we just import fantasy-options, I know people don't want more dependencies, but I don't want to envision lots of Maybes out in the wild. Everyone different to each other...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something that I have struggled to understand myself. There doesn't need to be multiple option/maybe/either implementations; and, I don't know why we can't specify what option/maybe/either is once and for all. Half of the ones out in the wild are broken anyway. Mostly they're not functors, but they claim to be. That's a worse situation than anything else. But the data types are simple and don't necessitate reinventing the wheel in every sub-community.

Not being able to speak about option/maybe/either also complicates the spec in ways that I think are more painful than forcing one data type onto people. Look at ChainRec. As far as I understand types, you can't really implement it. In order for it to be implementable, you need higher rank polymorphism. HIgher rank polymorphism is something that very few languages/tools support–flow and typescript do not support it. I don't think we gain much as a spec by forcing higher rank polymorphism on people. It's been hard enough to communicate higher kinded polymorphism.

If we can just speak about option/maybe/either: we won't have an unimplementable algebra, ChainRec will be easier to understand, and we can bring in more useful algebras–Filterable, Witherable, Choice, CoChoice, Decidable to name a few.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is my responce to this issue (scroll down)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry. I was venting. This PR is not the appropriate place for it. Do not let my comment stop progress of this PR. If it's something we are going to address, we should do it in another issue.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel the same way though :-(

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can discuss this in #200

a[map](f)[alt](b[map](f))
);

module.exports = {associativity, distributivity};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

T[zero]()
);

module.exports = {distributivity, annihilation};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

T[of](a)
);

module.exports = {leftCatch};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

x[chain](f)[alt](y[chain](f))
);

module.exports = {distributivity};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

T[zero]()
);

module.exports = {annihilation};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

T[zero]()
);

module.exports = {rightIdentity, leftIdentity, annihilation};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@SimonRichardson
Copy link
Member

Just one comment otherwise 🎉

@safareli
Copy link
Member Author

That's interesting point, suppose we depend on fantasy-id, fantasy-options, fantasy-compose ...

What would happen if someone adds other spec? how do you see for example process of adding some spec Foo with method foo?

Also fantasy-* libs have test on there own, we would test it twice? and they also depend on FL.

@safareli
Copy link
Member Author

safareli commented Oct 28, 2016

Possibly solution is to completely remove test from FL, but in this case fantasy-id, fantasy-maybe ... should be always up to date and if we have a PR to add some spec to FL, before we land it, PRs for fantasy-* should be opened, to ensure PR in FL is correct, then PR in FL could be merged and version bumped. After which PRs in fantasy-* could update FL and merge as well.

@safareli
Copy link
Member Author

safareli commented Oct 29, 2016

one issue is that Maybe is not MonadPlus but is MonadOr

mplus a b >>= f = mplus (a >>= f) (b >>= f)
a = Just 0
b = Just 1
f 0 = Nothing
f 1 = Just 1

so this will fail:

test(x => monadPlus.distributivity(equality)(Maybe.Just(0))(Maybe.Just(1))(
  a => a === 0 ? Maybe.Nothing : Maybe.Just(a)
))

Array is MonadPlus, but not MonadOr, so I have updated Array patch to test it against monadPlus laws.

- fix Maybe equals
- make Array Alternative and Monad
- test Array for MonadPlus
- test Maybe for MonadOr
@safareli
Copy link
Member Author

safareli commented Oct 31, 2016

At this point it's ready to be merged, But there is one thing, which I don't quite like:

If some structure has of we know that it's Apply and if it also has chain than it must be a Monad there are no other choices. on the other hand if structure has of , chain and alt than it must be MonadZero. Problem is that it could also be a MonadPlus or MonadOr. so we have 3 specs Monad{Zero,Plus,Or} and they are not distinguishable from each other.

I think it could be problematic in js (because of lack of type system), but it could also be problematic even in purescript?

f :: (Monad___ m) => m a ->  m a -> (a-> m b) -> m b
f m1 m2 g= (m1 `alt` b2) >>= g

I don't have strong opinion on it, maybe it's not a big dial and it's actually ok, but wanted to point it out. Also I would love to hear what @garyb and @paf31 think on it as in PS there is not MonadOr (yet).

-- update

in MonadPlus reform proposal MonadPlus is defining mplus and MonadOr is defining morelse, it's good beacause user of those methods knows how would it behave exactly, and maybe it's the way to go?

morelse and mplus would be aliases of alt if structure supports only one of them, but some could support both MonadPlus and MonadOr:

instance MonadPlus Maybe where
   mplus (Just a) Nothing = Just a
   mplus Nothing (Just a) = Just a
   mplus _ _ = Nothing

instance MonadOr Maybe where
  -- this is same as definition in Alternative
   morelse (Just a) _ = Just a
   morelse _ b = b

as well as []

instance MonadOr [] where
   morelse [] b = b
   morelse a b = a
instance MonadPlus [] where
  -- this is same as definition in Alternative
   mplus  = (++)

from MonadPlus reform proposal#Instances of both

@joneshf
Copy link
Member

joneshf commented Oct 31, 2016

If some structure has of we know that it's Apply and if it also has chain than it must be a Monad there are no other choices. on the other hand if structure has of , chain and alt than it must be MonadZero

Is that true? It seems like you can have something tha is Applicative and Chain, but doesn't satisfy the Monad laws. Similarly for MonadZero.

image was squashed because of `px` sizing.
@safareli
Copy link
Member Author

@joneshf technically one could make Validation a Chain but it's sort of cheating.

So to be precise if structure is Applicative(of,ap) and Chain(chain) than we have two choices

  • Applicative+Chain
  • Applicative+Chain+Monad

if structure is Applicative(of,ap) Alternative(alt,zero) and Chain(chain) then we have 4 choices:

  • Applicative+Alternative+Chain
  • Applicative+Alternative+Chain+MonadZero
  • Applicative+Alternative+Chain+MonadZero+MonadOr
  • Applicative+Alternative+Chain+MonadZero+MonadPlus

@rpominov
Copy link
Member

rpominov commented Oct 31, 2016

I wouldn't care too much about detection of supported algebras by presence of methods. If this will become a real problem we can solve it for example by requiring values to have fantasy-land/algebras property that points to an array like ['Funcor', 'Apply', 'Applicative'].

But we should think about structures that may support both MonadPlus and MonadOr, as far as I understand.

@safareli
Copy link
Member Author

But we should think about structures that may support both MonadPlus and MonadOr, as far as I understand.

Exactly.

In that case we should have separate methods for MonadPlus and MonadOr. in the haskell proposal names: mplus and morelse are used, if we use them I think they should be camelCase: mPlus, mOrElse.

if structure is MonadPlus or MonadOr it could define alt using mPlus or mOrElse.

T.prototype[fl.mOrElse] = T.prototype[fl.alt] = function(a) { .... }
T.prototype[fl.mPlus] = T.prototype[fl.alt] = function(a) { .... }

do others agree on the names?

@safareli
Copy link
Member Author

safareli commented Nov 1, 2016

I think it's ready for final review and then it could be merged 🎉 🌮

@@ -25,7 +28,7 @@ structures:
* [Bifunctor](#bifunctor)
* [Profunctor](#profunctor)

<img src="figures/dependencies.png" width="863" height="347" />
<img src="figures/dependencies.png" width="100%" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this will reintroduce the problem @rpominov fixed in #119.

Copy link
Member Author

@safareli safareli Nov 2, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix that. We definitly need CONTRIBUTING.md

Copy link
Member Author

@safareli safareli Nov 2, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on github the width of README is fixed but for example on npm it looks bad because max width of readme area is 727px and if you are on small screan than it's worth.

screen shot 2016-11-02 at 5 45 06 pm

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, same issue with mobile version of GitHub for example. I wish we could find a fix without this side effect, but in the current situation having links to point to the right locations is more important imo.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok will change it as it was before.

But we could move the image to the end of README and have a link in it's place where it was before (next to list of specs) and also a link back.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for moving to the end.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can check rendered image here

#### `zero` method

```hs
zero :: Plus x => () -> x
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be Plus x => () -> x a? Also maybe use p instead of x?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case we should also add forall a I think, but i'm not familiar with that. maybe @joneshf could help here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think forall is kinda implicit in our loosely specified type system. What I was trying to say is that x is not a type here, it's a type constructor, so it cannot be in that position in signature. x a is a type on the other hand.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use f a. f to be consistent with other types

Copy link
Member

@rpominov rpominov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@safareli
Copy link
Member Author

safareli commented Nov 2, 2016

@SimonRichardson @davidchambers I think it's ready to be merged ⏲

@SimonRichardson
Copy link
Member

I'll check tomorrow if that's ok

On Wed, 2 Nov 2016, 18:11 Irakli Safareli, notifications@github.com wrote:

@SimonRichardson https://github.com/SimonRichardson @davidchambers
https://github.com/davidchambers I think it's ready to be merged ⏲


You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub
#197 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ACcaGFxlV8irMSnODLUh-iPfwfuL6L4tks5q6NJKgaJpZM4KiYeK
.

@safareli
Copy link
Member Author

safareli commented Nov 4, 2016

⏰ a friendly reminder

@SimonRichardson
Copy link
Member

@safareli sorry, I looked at this yesterday and forgot to 👍

MERGE IT
🌮

@davidchambers
Copy link
Member

Would you mind squashing the commits, @safareli? It would be nice to avoid mentioning MonadZero, MonadOr, and MonadPlus in the commit history to avoid confusion.

@safareli safareli changed the title Add Alternative specs Add Alt, Plus and Alternative specs Nov 4, 2016
@safareli
Copy link
Member Author

safareli commented Nov 4, 2016

I think this commits might be useful in future for reference. And as I remember before my committee where Squash and Merged. can we do it again? if yes then commit message will be

Add Alt, Plus and Alternative specs (#197)

And for it's description we could just say that tests where refactored a bit:

- refactor tests
- 'id.js' moved to 'internal/'

if you want to just Rebase and Merge I could squash changes but the monad zero... stuff will be lost.

@davidchambers davidchambers merged commit 9ca844c into fantasyland:master Nov 4, 2016
@davidchambers
Copy link
Member

Thanks for updating the pull request's title and providing an appropriate commit message. :)

Shall we release v2.1.0?

@safareli safareli deleted the alternative branch November 4, 2016 14:37
@safareli
Copy link
Member Author

safareli commented Nov 4, 2016

I think yes 🎈

@rpominov
Copy link
Member

rpominov commented Nov 5, 2016

Yea, releasing a new version would be nice. I need it to add this algebras to static-land.

rjmk added a commit to rjmk/fantasy-land that referenced this pull request Nov 12, 2016
* 'master' of github.com:fantasyland/fantasy-land: (29 commits)
  Version 2.1.0
  Add Alt, Plus and Alternative specs (fantasyland#197)
  Use uppercase letters for Type representatives in laws (fantasyland#196)
  Fix id_test and argument order in laws (fantasyland#193)
  Version 2.0.0
  Another go at updating dependencies (fantasyland#192)
  release: integrate xyz (fantasyland#191)
  test: remove unnecessary lambdas (fantasyland#190)
  require static methods to be defined on type representatives (fantasyland#180)
  lint: integrate ESLint (fantasyland#189)
  Enforce parametricity (fantasyland#184)
  readme: tweak signatures to indicate that methods are not curried (fantasyland#183)
  Fix reduce signature to not use currying (fantasyland#182)
  Link to dependent specifications (fantasyland#178)
  Add Fluture to the list of implementations (fantasyland#175)
  laws/functor: fix composition (fantasyland#173)
  laws/monad: fix leftIdentity (fantasyland#171)
  Minor version bump
  bower: add bower.json (fantasyland#159)
  Fix chainRec signature to not use currying (fantasyland#167)
  ...
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

Successfully merging this pull request may close these issues.

Add spec for Alt, Plus, Alternative
6 participants