Skip to content

RFC: Implicit parentheses in GHCi

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

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:

>>> :t (:$)
>>> :t (Op Add :$)
>>> :t Op Add :$ Lit 10
>>> :t (:$)
>>> :t (Op Add :$)
>>> :t (Op Add :$) (Lit 10)
>>> :t (:$)
>>> :t (:$) (Op Add)
>>> :t (:$) (Op Add) (Lit 10)
>>> :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:

  >>>
  >>> :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:

  >>>
  >>> :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:

  >>>
  >>> :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..))

  >>> :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:

  >>>
  >>> :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:

>>> :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:

>>> :t >>=
>>> :t >>= id

and could be extended to work with infix functions as well, I would probably use flip a whole lot less:

>>> :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.

Trac metadata
Trac field Value
Version 8.0.1
Type FeatureRequest
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component GHCi
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information