Skip to content

RFC: pp using forall notation for all pi types from a Type to a Prop #1834

@kmill

Description

@kmill

The following shows the current way that many common variations on pi types are pretty printed:

variable (α : Nat → Type) (p q : Prop) (P : Nat → Prop)

#check (i : Nat) → Nat  -- Nat → Nat
#check {i : Nat} → Nat  -- {i : Nat} → Nat
#check (h : p) → q      -- p → q
#check (i : Nat) → p    -- Nat → p
#check (i : Nat) → α i  -- (i : Nat) → α i
#check {i : Nat} → α i  -- {i : Nat} → α i
#check (i : Nat) → P i  -- ∀ (i : Nat), P i
#check {i : Nat} → P i  -- ∀ {i : Nat}, P i
#check {i : Nat} → p    -- ∀ {i : Nat}, p

This RFC is primarily about the Nat → p case, which tends to be the most surprising (it is a source of questions on Zulip). This sort of Prop-valued pi type frequently appears in the course of rewrites, where a forall quantifier becomes non-dependent:

example (P : Nat → Prop) (q : Prop) (h : ∀ n, P n = q) (hq : q) :
  ∀ n, P n :=
by
  simp [h]
  -- ⊢ Nat → q
  exact λ _ => hq

The meaning of a non-dependent pi from a Type to a Prop is generally a universal quantification, so the pretty printer should represent such pi types in some way such that this is clear.

Concretely, given ι : Sort u and α : ι → Sort v, then when u > 0 and v = 0 we should make sure to use when pretty printing the corresponding pi type for α, even if the pi type is nondependent.

The nondependent u = 0 and v = 0 case should be left alone since the implication arrow serves its purpose just fine.


There are a couple of additional considerations presentation-wise.

While pretty printing pi types using gives the user the information that it is Prop-valued, this leads to the user not being able to immediately see whether the quantifier is dependent or not; in discussion, it was brought up that this information is important for expert Lean users. One possible solution to this is to pretty print Nat → p as ∀ (_ : Nat), p (rather than ∀ (i : Nat), p) with a placeholder for the variable. This way one can immediately see it is a Prop-valued non-implication non-dependent pi type.

This leads to some inconsistency when it comes to non-default binders for other nondependent pi types. One might entertain using placeholders in every context where a non-dependent pi would print a binder. For example, {_ : Nat} → Nat rather than {i : Nat} → Nat. This does lead to loss of information that is important for (i := 22) argument notation. There are other solutions (such as using a tombstone, or using semantic coloring in an editor), or we can simply choose to tolerate any potential inconsistency here.

In a similar direction, for instance binders we currently have

#check (α : Type) → [DecidableEq α] → True
-- ∀ (α : Type) [inst : DecidableEq α], True

With suggestions above, this would pretty print as ∀ (α : Type) [_ : DecidableEq α], True since the instance binder is non-dependent, but one may as well pretty print it as ∀ (α : Type) [DecidableEq α], True since it gives the same amount of information while looking prettier.

(The Lean 3 version of this RFC is lean PR 770.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    P-lowWe are not planning to work on this issueRFCRequest for comments

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions