thoughtbot / carnival

An unobtrusive, developer-friendly way to add comments
MIT License
499 stars 30 forks source link

Explain how to open a REPL #138

Closed gabebw closed 9 years ago

jferris commented 9 years ago

Is cabal exec ghci preferable to cabal repl?

cc @thoughtbot/haskell

pbrisbin commented 9 years ago

They do different things, and I find cabal repl not useful in the context of Yesod app (or in general really).

Specifically, cabal repl launches in the context of your executable, which typically has very little imported:

% cabal repl
λ> :browse
makeApplication :: AppConfig DefaultEnv Extra -> IO Application
makeFoundation :: AppConfig DefaultEnv Extra -> IO App
getApplicationDev :: IO (Int, Application)

Compared with opening a module (any module), which gives you immediate access to everything:

% cabal exec -- ghci Model.hs
λ> :browse
type Token = Text
type Validated a = Either [Text] a
type Validation a = a -> Validated a
type SubscriptionId = Key Subscription
data Subscription
  = Subscription {subscriptionName :: !Text,
                  subscriptionUser :: !Key User,
                  subscriptionToken :: !Token,
                  subscriptionActive :: !Bool}
type CommentId = Key Comment
data Comment
  = Comment {commentUser :: !Key User,
             commentArticleURL :: !Text,
             commentArticleTitle :: !Text,
             commentArticleAuthor :: !Text,
             commentThread :: !Text,
             commentBody :: !Markdown,
             commentCreated :: !UTCTime}
type UserId = Key User
data User
  = User {userName :: !Text,
          userEmail :: !Text,
          userPlugin :: !Text,
          userIdent :: !Text}

... and so on

The (only?) downside is that cabal exec -- ghci bypasses your cabal file. That means you might get everything compiling this way then have to follow up separately (with cabal run or cabal build) to catch things like missing depends or exposed modules. I don't mind this myself, but cabal repl would catch these issues as you work which some may prefer.

jferris commented 9 years ago

Specifically, cabal repl launches in the context of your executable

By default, it uses the first component listed in your .cabal file, which is always the library for me. You can override it if you prefer a different component.

Compared with opening a module (any module), which gives you immediate access to everything

I like that it opens a specific module, but I do wish cabal repl accepted a module to start with. You can use :m or import like normal ghci, though:

 % cabal repl
Preprocessing library carnival-0.0.0...
GHCi, version 7.8.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
...
[ 1 of 24] Compiling Network.Mail.SendGrid ( Network/Mail/SendGrid.hs, interpreted )
...
[24 of 24] Compiling Application      ( Application.hs, interpreted )
Ok, modules loaded: Application, Import, Settings, Handler.Comments, Handler.Session, Handler.Embed, Handler.User, Handler.Feed, Handler.Unsubscribe, Foundation, Settings.Development, Settings.StaticFiles, Model, Model.Comment, Model.Subscription, Model.User, Model.UserComment, SendMail, Network.Mail.RecipientOverride, Network.Mail.SendGrid, Notification, Helper.Auth, Helper.Request, Helper.Validation.
*Application> import Model
*Application Model> :info User
data User
  = User {userName :: !Text,
          userEmail :: !Text,
          userPlugin :: !Text,
          userIdent :: !Text}
    -- Defined at Model.hs:21:1
instance Eq (Key User) -- Defined at Model.hs:21:1
instance Eq User -- Defined at Model.hs:21:1
instance Ord (Key User) -- Defined at Model.hs:21:1
instance Read (Key User) -- Defined at Model.hs:21:1
instance Show (Key User) -- Defined at Model.hs:21:1
instance Show User -- Defined at Model.hs:21:1
instance PersistField User -- Defined at Model.hs:21:1
instance PersistField (Key User) -- Defined at Model.hs:21:1
instance PersistEntity User -- Defined at Model.hs:21:1
instance PathPiece (Key User) -- Defined at Model.hs:21:1
instance ToJSON (Entity User) -- Defined at Model/User.hs:15:10
instance ToJSON (Key User) -- Defined at Model.hs:21:1
instance FromJSON (Key User) -- Defined at Model.hs:21:1
data Unique User -- Defined at Model.hs:21:1
type PersistEntityBackend User -- Defined at Model.hs:21:1
newtype Key User -- Defined at Model.hs:21:1
data EntityField User -- Defined at Model.hs:21:1
pbrisbin commented 9 years ago

By default, it uses the first component listed in your .cabal file, which is always the library for me. You can override it if you prefer a different component.

I tried to look this up / figure this out and couldn't. Do you get different :browse output than I do, using the same (Carnival's) cabal file? How do I make it use the library target, which I assume has everything exported by all exposed modules? Or is it, but my assumption about the modules I'd get is wrong?

jferris commented 9 years ago

Do you get different :browse output than I do, using the same (Carnival's) cabal file?

No, if I follow your example, I get the same result. Because cabal repl doesn't accept a module, you'll need to do :load Model and then :browse (or just :browse Model).

My understanding of ghci is that:

In cabal repl, it seems to use the first listed module of the first component. All other modules are loaded but not in scope unless you use :module or import.

jferris commented 9 years ago

Looks like they plan to add it:

Support for loading specific modules is planned but not implemented yet.

(from cabal help repl)

pbrisbin commented 9 years ago

In cabal repl, it seems to use the first listed module of the first component

That's seems pretty useless to me. I stand by my preference for ghci.

jferris commented 9 years ago

@gabebw I think your change is good to merge.