Zulip Chat Archive

Stream: new members

Topic: Constructors and constants


Logan Murphy (Jul 09 2020 at 12:43):

Hello! Trying to formalize labelled transition systems by building some types and structures. If I write something like

constant foo : Type
structure bar :=
mk :: (x : foo)

constant f : foo
def baz := bar.mk f

Lean complains that 'baz' is noncomputable and depends on 'f'. What is the problem?
As a counterexample, I can write

structure bar' := mk ::
(x : nat)

def baz' := bar'.mk 10

which behaves as expected. Why can Lean do this with nat's but not with constants of type foo?

Scott Morrison (Jul 09 2020 at 12:50):

I suspect constant doesn't mean what you think it means.

Scott Morrison (Jul 09 2020 at 12:50):

Using constant is adding a new axiom to your logical foundations.

Scott Morrison (Jul 09 2020 at 12:51):

In particular, one without a computational interpretation, and hence anything using it becomes noncomputable.

Scott Morrison (Jul 09 2020 at 12:51):

Generally, I would avoid entirely using constant or parameter.

Scott Morrison (Jul 09 2020 at 12:51):

variables is probably better

Logan Murphy (Jul 09 2020 at 12:52):

Ah, thank you very much Scott.

Logan Murphy (Jul 09 2020 at 13:16):

I was able to get the desired behavior just using an enumerated type.
If I can ask another question about building structures, let's say I define an LTS structure as follows.

inductive state
| s₁
| s₂
| s₃
| s₄
open state

inductive label
| l₁
| l₂
| l₃
| l₄
open label

structure LTS :=
mk :: (S : set state) (A : set label) (Δ : set (state × label × state))
open LTS

def M₁ : LTS :=  mk {s₁, s₂, s₃, s₄} {l₁, l₂, l₃, l₄} {(s₁, l₂, s₃), (s₃, l₁, s₄)}

When I query #reduce M₁, the result is abstracted over the arguments I've provided to the mk constructor. The result is

{S := λ (b : state), b = s₁  b = s₂  b = s₃  b = s₄,
 A := λ (b : label), b = l₁  b = l₂  b = l₃  b = l₄,
 Δ := λ (b : state × label × state), b = (s₁, l₂, s₃)  b = (s₃, l₁, s₄)}

when I would expect something like
{ S := { s₁, s₂, s₃, s₄ }
A := { l₁, l₂, l₃, l₄ },
Δ := { (s₁, l₂, s₃), (s₃, l₁, s₄) } }

Reid Barton (Jul 09 2020 at 13:18):

λ (b : state), b = s₁ ∨ b = s₂ ∨ b = s₃ ∨ b = s₄ is the reduced form of { s₁, s₂, s₃, s₄ }, and so on.

Logan Murphy (Jul 09 2020 at 13:19):

Ok great, thank you very much!

Logan Murphy (Jul 09 2020 at 15:59):

Based on what I've read, it seems like to only way to have a structure's fields refer to one another is to use inheritance. For instance, I can define the structure

structure LTS  :=
mk :: (S : set state) (A : set label) (TransRel : set (state × label × state))

but I want to be able to limit TransRel to those triples formed of the sets S and A. One approach I tried was

structure foo := (S : set state) (A : set label)
structure LTS extends foo := (TransRel : S × A × S)

but it seems I can't form Cartesian products in this way. Is it clear at all what I could do to achieve this?

Reid Barton (Jul 09 2020 at 16:05):

structure LTS  :=
mk :: (S : set state) (A : set label) (TransRel : set (S × A × S))

works for me (with appropriate context)

Reid Barton (Jul 09 2020 at 16:05):

though I would guess (S : set state) (A : set label) is likely a mistranslation of what you actually want

Reid Barton (Jul 09 2020 at 16:10):

for example, maybe you actually want

structure LTS  :=
mk :: (S : Type) (A : Type) (TransRel : set (S × A × S))

Logan Murphy (Jul 09 2020 at 16:19):

You're probably right. Thank you!

Logan Murphy (Jul 09 2020 at 16:20):

(deleted)

Logan Murphy (Jul 09 2020 at 16:30):

The reason I wanted to define a type of state and use sets thereof was so I could do things like

def M₁ : LTS :=  mk {s₁, s₂, s₃, s₄} {l₁, l₂, l₃, l₄}
{(s₁, l₂, s₃), (s₃, l₁, s₄), (s₄, l₃ , s₂), (s₂, l₄, s₅)}

is there a way to do such a thing with the presentation you offered? Sorry for the noob questions, I'm still getting used to using dependent TT this way

Reid Barton (Jul 09 2020 at 16:35):

looks like

def M₁ : LTS :=  mk state label
{(s₁, l₂, s₃), (s₃, l₁, s₄), (s₄, l₃ , s₂), (s₂, l₄, s₅)}

Reid Barton (Jul 09 2020 at 16:35):

(I'm assuming you might want to define other LTSs with other state and label types.)

Logan Murphy (Jul 09 2020 at 16:37):

Definitely better. Thanks!

Logan Murphy (Jul 09 2020 at 16:52):

Ok, now I think the only other reason I'd be tempted to use sets of states and labels is so that I can use membership to inductively define executions within an LTS, in the (general) sense of

structure sl_pair :=
makepair :: (s : state) (l : label)

-- Given any Labelled Transition System M,
-- given any state s₀ ∈ M.S, (init s₀) is an execution
-- given any execution e which "finishes" at a state s,
--      can form an execution e' by appending
--      state-label pair (s', l) to e such that
--      (s, l, s') ∈ M.TransRel

/- skeleton of inductive definition -/
inductive execution {M : LTS}
| init : state  execution
| cons : sl_pair  execution  execution

So I'm trying to implement the logic in the comments into this definition, and one approach I guess would be to supply membership-propositions as arguments to the constructors, if I use the set-theoretic definition of LTS. But there may very well be an approach using the simpler type-theoretic definition as well.

Reid Barton (Jul 09 2020 at 16:59):

It looks like it will just be the same, but without any set membership involved.

Logan Murphy (Jul 09 2020 at 17:00):

Ok, will play around. Thanks again!


Last updated: Dec 20 2023 at 11:08 UTC