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 haddocks for capabilities #33

Merged
merged 6 commits into from
Sep 25, 2018
Merged

Add haddocks for capabilities #33

merged 6 commits into from
Sep 25, 2018

Conversation

aherrmann
Copy link
Member

@aherrmann aherrmann commented Sep 5, 2018

Question: Is there an authoritative source for the laws? (See mtl issue linked from the diff)

  • Adds haddock documentation for capability classes and their methods.
  • Adds (not yet definitive) laws based on the discussion in Missing laws haskell/mtl#5.
  • Documents sources for laws in LOG.md.

@aherrmann
Copy link
Member Author

Define the reader and state laws in terms of ask,local; get,`put.

Add a LOG.md listing sources for the laws.

Document that these are not necessarily definitive.

@aherrmann aherrmann requested a review from aspiwack as a code owner September 21, 2018 13:10
@aherrmann aherrmann changed the title [WIP] Add haddocks for capabilities Add haddocks for capabilities Sep 21, 2018
@aherrmann aherrmann requested a review from mboes September 24, 2018 08:37
Copy link
Member

@aspiwack aspiwack left a comment

Choose a reason for hiding this comment

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

I posit that we can do much better. Sorry to push this on you so late.

I've gone through the Reader haddock strings. This should give you enough material to go update the rest.

class Monad m
=> HasReader (tag :: k) (r :: *) (m :: * -> *) | tag m -> r
where
-- | Use 'ask' instead.
Copy link
Member

Choose a reason for hiding this comment

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

« For technical reasons, this method needs an extra proxy argument. You only need if you are defining new instances of 'HasReader'. In other case, you will want to use 'ask'. See 'ask' for more documentation. »

(and similarly on all the methods. I know it's a bit tedious, but it is absolutely worth it)

reader_ :: Proxy# tag -> (r -> a) -> m a

-- | @ask \@tag@
-- Retrieve the environment.
Copy link
Member

Choose a reason for hiding this comment

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

« retrieves » (final s, no capital letters).

I'd even put it like this: « @ask \@tag@ retrieves the environment of the reader capability @\@tag@. »

ask :: forall tag r m. HasReader tag r m => m r
ask = ask_ (proxy# @_ @tag)
{-# INLINE ask #-}

-- | @asks \@tag@
-- Retrieve a projection of environment according to @f@.
Copy link
Member

Choose a reason for hiding this comment

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

How about @asks \@tag f = f <$> ask \@tag@ ? It's quite a bit less confusing. I'm not sure that there is a way to clarify further.

An English translation of this would be « @asks \@tag f@ retrieves the image, by @f@ of the environment of the reader capability @\@tag@. » You can have this. But the straightfoward definition should definitely be there too.

-- | @asks \@tag@
-- Retrieve a projection of environment according to @f@.
--
-- XXX: Seems identical to 'reader'. Is 'asks' redundant?
Copy link
Member

Choose a reason for hiding this comment

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

No XXX in haddock comments. But yes, it's the same as reader, though their intent is a bit different. In fact, in the mtl, asks is defined as reader.

asks :: forall tag r m a. HasReader tag r m => (r -> a) -> m a
asks f = f <$> ask @tag
{-# INLINE asks #-}

-- | @local \@tag f m@
-- Execute @m@ with the environment updated according to @f@.
Copy link
Member

Choose a reason for hiding this comment

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

« @local \@tag f m@ runs the monadic action @m@ in a modified environment @e' = f e@, where @e@ is the environment of the reader capability @\@tag@. Symbolically: @return e = ask \@tag@. »

local :: forall tag r m a. HasReader tag r m => (r -> r) -> m a -> m a
local = local_ (proxy# @_ @tag)
{-# INLINE local #-}

-- | @reader \@tag@
Copy link
Member

Choose a reason for hiding this comment

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

@reader \@tag act@ lifts a purely environment-dependent action @act@ to a monadic action in an arbitrary monad @m@ with capability @HasReader@.

It happens to coincide with @asks@: @reader = asks@.

@aherrmann
Copy link
Member Author

@aspiwack Ready for another round.

Copy link
Member

@aspiwack aspiwack left a comment

Choose a reason for hiding this comment

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

Minor changes below. Then merge.

ask :: forall tag r m. HasReader tag r m => m r
ask = ask_ (proxy# @_ @tag)
{-# INLINE ask #-}

-- | @asks \@tag@
-- retrieves the image, by @f@ of the environment
Copy link
Member

Choose a reason for hiding this comment

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

no comma here.

state_ :: Proxy# tag -> (s -> (a, s)) -> m a

-- | @get \@tag@
-- retrieve the current state of the state capability @\@tag@.
Copy link
Member

Choose a reason for hiding this comment

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

I just realised that in this phrasing, we should say the state capability @tag@ without the \@. We should clean that everywhere, I suppose.

state :: forall tag s m a. HasState tag s m => (s -> (a, s)) -> m a
state = state_ (proxy# @_ @tag)
{-# INLINE state #-}

-- | @modify \@tag f@
-- given the current state @s@ of the state capability @\@tag@
-- and @s' = f s@, update the state to @s'@.
Copy link
Member

Choose a reason for hiding this comment

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

update -> updates.
By symmetry: update the state of the capability @tag@.

modify' :: forall tag s m. HasState tag s m => (s -> s) -> m ()
modify' f = do
s' <- get @tag
put @tag $! f s'
{-# INLINE modify' #-}

-- | @gets \@tag f@
-- retrieves the image, by @f@ of the current state
-- of the state capability @\@tag@.
Copy link
Member

Choose a reason for hiding this comment

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

Add the definitional rule in terms of get like in reads.

yield_ :: Proxy# tag -> a -> m ()

-- | Emit the given value.
-- | Emit the given value in the given stream capability.
Copy link
Member

Choose a reason for hiding this comment

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

As usual @yield \@tag a@ emits @a@ in the stream capability @tag@.

pass_ :: Proxy# tag -> m (a, w -> w) -> m a

-- | @writer \@tag (a, w)@
-- writes @w@ to the output of the writer capability @\@tag@
Copy link
Member

Choose a reason for hiding this comment

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

This should be « lifts a pure, etc… »

writer :: forall tag w m a. HasWriter tag w m => (a, w) -> m a
writer = writer_ (proxy# @_ @tag)
{-# INLINE writer #-}

-- | @tell \@tag w@
-- writes @w@ to the output of the writer capability @\@tag@.
Copy link
Member

Choose a reason for hiding this comment

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

not « writes »: appends. Since it is the word used in Haskell for monoid thingies.

put :: forall tag s m. HasState tag s m => s -> m ()
put = put_ (proxy# @_ @tag)
{-# INLINE put #-}

-- | @state \@tag f@
-- given the current state @s@ of the state capability @\@tag@
-- and @(a, s') = f s@, update the state to @s'@ and return @a@.
Copy link
Member

Choose a reason for hiding this comment

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

This should be « lifts a pure, yada yada ».

tell :: forall tag w m. HasWriter tag w m => w -> m ()
tell = tell_ (proxy# @_ @tag)
{-# INLINE tell #-}

-- | @listen \@tag m@
-- executes the action @m@ and returns the output of @m@
-- in the writer capability @\@tag@ along with result of @m@.
Copy link
Member

Choose a reason for hiding this comment

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

What does it output? The output of @m@? mempty?

-- | @pass \@tag m@
-- executes the action @m@. Assuming @m@ returns @(a, f)@ and writes
-- @w@ to the output of the writer capability @\@tag@.
-- @pass \@tag m@ instead writes @w' = f w@ to the output and returns @a@.
Copy link
Member

Choose a reason for hiding this comment

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

writes -> appends

@aherrmann aherrmann merged commit 5cf9a8a into master Sep 25, 2018
@aherrmann aherrmann deleted the haddock-laws branch September 25, 2018 13:43
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.

2 participants