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

make new user experience smoother #350

Closed
wants to merge 3 commits into from

Conversation

codygman
Copy link

This adds some noise, which I'm not a huge fan of. However if I hadn't
had my cup of coffee and not tried reading the type error, I might have
pushed back "actually use polysemy in the real world" to "later".

Ideally I think I would have read the docs, but I suspect that "paste
examples verbatim into ghc source file without reading docs" is a
popular method to try libraries out.

Fixes #349

This adds some noise, which I'm not a huge fan of. However if I hadn't
had my cup of coffee and not tried reading the type error, I might have
pushed back "actually use polysemy in the real world" to "later".

Ideally I think I would have read the docs, but I suspect that "paste
examples verbatim into ghc source file without reading docs" is a
popular method to try libraries out.

Fixes polysemy-research#349
@TheMatten
Copy link
Collaborator

Hmm - it would make complete sense this way - I just wonder whether it wouldn't be better idea to instead just ask people to enable plugin, because that's how library is meant to be used in most cases.

Maybe we could turn that example into stack/cabal script, so that user does not need any manual configuration to try it out as a self-contained file.

I think the thought here is to assume the plugin is used. If that's the
case, at least on ghc 8.8.3, the type application isn't needed on catch
with polysemy-plugin enabled.

Added comment about needing type application without the plugin in line
with the reason for this PR for users who might just copy/paste to try polysemy.
@codygman
Copy link
Author

That sounds great to me. Basically anything where the user can paste it in, run it, and start modifying it is awesome.

On a longer more rambly note, I wasn't sure about the ideal answer, I just answered the immediate question of "how would I have been able to more quickly get the example working?" which I think a stack/cabal script solves as well

Ideally I and everyone else would read the docs (maybe) and install the plugin, but I could see an argument that "try quickly by pasting code examples" is necessary in today's tech world.

One could assume that after clicking through to
"necessary-language-extensions" and pasting the list in:

    - DataKinds
    - FlexibleContexts
    - GADTs
    - LambdaCase
    - PolyKinds
    - RankNTypes
    - ScopedTypeVariables
    - TypeApplications
    - TypeOperators
    - TypeFamilies

That you'd be done with adding language extensions. That's the mistake I
just made anyway :)

This is just a note to help others avoid that mistake.
@codygman
Copy link
Author

I'm trying to use runTeletypePure. In order to do that and understand it I wanted to understand the types in ghci. That brings about my question which I think might be a ghci limitation... Can I get better type signatures using the symbols from the Polysemy docs? Because after :load MyFile.hs with the teletype example in ghci I get this:

*Main> :t program
program
  :: (Polysemy.Internal.Union.Find (Error CustomException) r,
      Polysemy.Internal.Union.Find Teletype r,
      Polysemy.Internal.Union.Find Resource r,
      Polysemy.Internal.Union.LocateEffect Teletype r ~ '(),
      Polysemy.Internal.Union.LocateEffect Resource r ~ '(),
      Polysemy.Internal.Union.LocateEffect (Error CustomException) r
      ~ '()) =>
     Sem r ()

Rather than the type in the source file of:

program :: Members '[Resource, Teletype, Error CustomException] r => Sem r ()

Maybe this is something the plugin can be extended to help with or a ghci feature I don't know about can be enabled?

@TheMatten
Copy link
Collaborator

Here's a header that should enable everything important in stack script:

#!/usr/bin/env stack
{- stack exec ghci
   --resolver lts-16.2
   --package  polysemy-1.3.0.0
   --package  polysemy-plugin-0.2.5.0
   --package  ghc-tcplugins-extra-0.3.2
 -}

{-# options_ghc -fplugin=Polysemy.Plugin #-}
{-# language    BlockArguments           #-}
{-# language    DataKinds                #-}
{-# language    FlexibleContexts         #-}
{-# language    GADTs                    #-}
{-# language    LambdaCase               #-}
{-# language    PolyKinds                #-}
{-# language    RankNTypes               #-}
{-# language    ScopedTypeVariables      #-}
{-# language    TemplateHaskell          #-}
{-# language    TypeApplications         #-}
{-# language    TypeOperators            #-}

import Polysemy

When run as an executable, or with stack Filename.hs, user gets spawned into ghci session with file and all it's dependecies loaded.

@TheMatten
Copy link
Collaborator

@codygman use :i, not :t - the former preserves signatures as written in source.

@codygman
Copy link
Author

@codygman use :i, not :t - the former preserves signatures as written in source.

Thanks, that fixes that case but it looks like I made the X-Y problem mistake 😞

There isn't a good answer to preserve signatures equivalent to :t program & runError is there?

*Main Data.Function> :t program & runError
program & runError
  :: (Polysemy.Internal.Union.Find Teletype r,
      Polysemy.Internal.Union.Find Resource r,
      Polysemy.Internal.Union.LocateEffect Teletype r ~ '(),
      Polysemy.Internal.Union.LocateEffect Resource r ~ '()) =>
     Sem r (Either CustomException ())

Just for completeness sake, I tried :i but was already sure it wouldn't do it:

*Main Data.Function> :i program & runError
program ::
  Members '[Resource, Teletype, Error CustomException] r => Sem r ()
  	-- Defined at switch.hs:45:1
(&) :: a -> (a -> b) -> b 	-- Defined in ‘Data.Function’
infixl 1 &
runError :: Sem (Error e : r) a -> Sem r (Either e a)
  	-- Defined in ‘Polysemy.Error’

@TheMatten
Copy link
Collaborator

Sadly that's limitation of GHC - we would need some way to tell it to not expand specific types/parameters when printing.

@codygman
Copy link
Author

codygman commented Jun 21, 2020

I'm not sure exactly where it fits in, but one reason I want to use polysemy is to more easily support the workflow of writing pure code and tests for it, then writing the effectful interpreter, and everything just working.

To that end I found the effectful example in the readme good, but it was left as an exercise to the reader to figure out how to use the pure version of the interpreter.

Maybe we could change this:

main :: IO (Either CustomException ())
main =
    runFinal
  . embedToFinal @IO
  . resourceToIOFinal
  . errorToIOFinal @CustomException
  . teletypeToIO
  $ program

To this:

main :: IO (Either CustomException ())
main = do
  putStrLn "run program purely"
  print . run . runTeletypePure ["foo"] . runResource . runError $ program
  putStrLn "run program in IO"
  runFinal
    . embedToFinal @IO
    . resourceToIOFinal
    . errorToIOFinal @CustomException
    . teletypeToIO
    $ program

@@ -103,7 +103,8 @@ import Polysemy.Internal.Union
-- catching = do
-- modify (++"-catch")
-- get
-- catch @String throwing (\ _ -> catching)
-- -- Without `-fplugin=Polysemy.Plugin` you need `catch @String`
Copy link
Member

Choose a reason for hiding this comment

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

Nit:
Since these are Haskell comments, maybe the backticks should be @s instead? Not sure if haddock even checks nested comments.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Haddock doesn't check these AFAIK

@@ -80,7 +80,7 @@ will be true in GHC 8.10.1.
## Examples

Make sure you read the [Necessary Language
Extensions](https://github.com/isovector/polysemy#necessary-language-extensions)
Extensions](https://github.com/isovector/polysemy#necessary-language-extensions) and add any extras in example source blocks (such as LambdaCase and BlockArguments below)
Copy link
Member

Choose a reason for hiding this comment

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

I really don't understand this sentence, sorry! Can you explain it to me? Mostly, what are the "extras" referring to?

Copy link
Author

Choose a reason for hiding this comment

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

extras == extra language pragmas

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, but what are they extra in reference to?
Do you mean "add any that are listed in the necessary extensions, but not enabled in the example source block"?

@TheMatten
Copy link
Collaborator

@codygman We could possibly define two separate functions instead:

main :: Either CustomException ([String], ())
main
  = run
  . runResource
  . runError
  . runTeletypePure ["foo"]
  $ program

main' :: IO (Either CustomException ())
main'
  = runFinal
  . embedToFinal @IO
  . resourceToIOFinal
  . errorToIOFinal @CustomException
  . teletypeToIO
  $ program

@isovector
Copy link
Member

Closing this due to being stale. Please feel free to reopen if you still think it's something that should get pushed through!

@isovector isovector closed this Nov 23, 2021
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.

Hackage example does not work in source file
4 participants