[GHC] #12541: RFC: Implicit parentheses in GHCi

GHC ghc-devs at haskell.org
Fri Aug 26 01:27:19 UTC 2016


#12541: RFC: Implicit parentheses in GHCi
-------------------------------------+-------------------------------------
           Reporter:  Iceland_jack   |             Owner:
               Type:  feature        |            Status:  new
  request                            |
           Priority:  normal         |         Milestone:
          Component:  GHCi           |           Version:  8.0.1
           Keywords:                 |  Operating System:  Unknown/Multiple
       Architecture:                 |   Type of failure:  None/Unknown
  Unknown/Multiple                   |
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 I've been making a few tickets lately that aren't technical but small
 things that would streamline my interactive experience. Please close if
 this is not the place for it. ''Caveat lector'': long and boring read
 ahead.

 = Code =
 {{{#!hs
 data Op  = Add   | Mul                  deriving Show
 data Exp = Op Op | Lit Int | Exp :$ Exp deriving Show
 infixl :$
 }}}

 = Motivation =
 I often want to see the “progression” of applying an operator to arguments
 one by one. There are several ways of doing this:

 {{{#!hs
 >>> :t (:$)
 >>> :t (Op Add :$)
 >>> :t Op Add :$ Lit 10
 }}}

 {{{#!hs
 >>> :t (:$)
 >>> :t (Op Add :$)
 >>> :t (Op Add :$) (Lit 10)
 }}}

 {{{#!hs
 >>> :t (:$)
 >>> :t (:$) (Op Add)
 >>> :t (:$) (Op Add) (Lit 10)
 }}}

 {{{#!hs
 >>> :t (:$)
 >>> :t (:$) (Op Add)
 >>> :t Op Add :$ Lit 10
 }}}

 Look at all of those parentheses! Every step adds or removes (or requires
 navigation around) parentheses.

 = `tl;dr`: this is annoying to type =

 I'm writing this out in full not just because I get a sick joy out of it
 but to hammer the point home.

 === First example ===
 We wrap `:$` in parentheses, navigate around them to make a section and
 then remove them:

 {{{#!hs
   >>>
   >>> :t (:$)␣
 -- C-m

   >>>
 -- C-p
   >>> :t (:$)␣
 -- C-a
   >>> ␣:t (:$)
 -- C-f, C-f, C-f, C-f
   >>> :t (␣:$)
   >>> :t (Op Add ␣:$)
 -- C-m

   >>>
 -- C-p
   >>> :t (Op Add :$)␣
 -- C-h
   >>> :t (Op Add :$␣
   >>> :t (Op Add :$ Lit 10
 -- C-a
   >>> ␣:t (Op Add :$ Lit 10
 -- C-f, C-f, C-f
   >>> :t ␣(Op Add :$ Lit 10
 -- C-d
   >>> :t ␣Op Add :$ Lit 10
 }}}

 === Second example ===
 We wrap `:$` in parentheses, navigate around them to make a section and
 then wrap the argument in parentheses:
 {{{#!hs
   >>>
   >>> :t (:$)␣
 -- C-m

   >>>
 -- C-p
   >>> :t (:$)␣
 -- C-a
   >>> ␣:t (:$)
 -- C-f, C-f, C-f, C-f
   >>> :t (␣:$)
   >>> :t (Op Add ␣:$)
 -- C-m

   >>>
 -- C-p
   >>> :t (Op Add :$)␣
   >>> :t (Op Add :$) (Lit 10)␣
 }}}

 === Third example ===
 Wrap everything in parentheses, on a good day I will remember that the
 arguments need parentheses:
 {{{#!hs
   >>>
   >>> :t (:$)␣
 -- C-m

   >>>
 -- C-p
   >>> :t (:$)␣
   >>> :t (:$) (Op Add)␣
 -- C-m

   >>>
 -- C-p
   >>> :t (:$) (Op Add)␣
   >>> :t (:$) (Op Add) (Lit 10)␣
 }}}

 ((On every other day I will forget that `Op Add` is an application and
 write..))

 {{{#!hs
   >>> :t (:$)␣
   >>> :t (:$) Add␣
 -- M-b
   >>> :t (:$) ␣Add
   >>> :t (:$) (Op ␣Add
 -- C-e
   >>> :t (:$) (Op Add␣
   >>> :t (:$) (Op Add)␣
 }}}

 === Fourth example ===
 Wrap operator and argument, remove both pairs of parentheses:

 {{{#!hs
   >>>
   >>> :t (:$)␣
 -- C-m

   >>>
 -- C-p
   >>> :t (:$)␣
   >>> :t (:$) (Op Add)␣
 -- C-m

   >>>
 -- C-p
   >>> :t (:$) (Op Add)␣
 -- C-a
   >>> ␣:t (:$) (Op Add)
 -- C-f, C-f, C-f
   >>> :t ␣(:$) (Op Add)
 -- C-d, C-d, ...
   >>> :t ␣Op Add)
 -- C-e
   >>> :t Op Add)␣
 -- C-h
   >>> :t Op Add␣
   >>> :t Op Add :$ Lit 10␣
 }}}

 = Proposal =
 Long story short this involves a lot of manipulation of terms
 (deleting/rewriting, cutting/pasting), jumping around and adding or
 removing parentheses.

 My proposal is to make GHCi a bit smarter in how it accepts operators and
 sections, to a first approximation it would be as if there were implicit
 `'(' ++ cmd ++ ')'` around the command. Let's see how I picture this would
 work:

 {{{#!hs
 >>> :t :$
 >>> :t Op Add :$
 >>> :t Op Add :$ Lit 10
 }}}

 This may feel disconcerting since this is not valid syntax for operators
 or sections, but I think it would be fine. For example both `:info :$` and
 `:info (:$)` work. This would take me a lot less time to write! No
 parentheses and minimal jumping around.

 This would make it very simple to get the right section of an operator:

 {{{#!hs
 >>> :t >>=
 >>> :t >>= id
 }}}

 and could be extended to work with infix functions as well, I would
 probably use `flip` a whole lot less:
 {{{#!hs
 >>> :t `take`
 -- ^ probably shouldn't work, but allows for less skipping

 >>> :t `take` "wabalabadubdub"
 >>> :t 10 `take` "wabalabadubdub"
 }}}

 The reason why I said “to a first approximation” is that `:$) (Op Add`
 should obviously not be valid.

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/12541>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list