Zulip Chat Archive

Stream: lean4

Topic: newtype


Pi Lanningham (Dec 28 2021 at 23:47):

Is there a notion of newtype in lean? or should I just use a structure with one field?

Henrik Böving (Dec 28 2021 at 23:50):

Either that or a def, e.g. ReaderT is defined with a def

Arthur Paulino (Dec 28 2021 at 23:51):

Do you mean creating your own type? Maybe constant MyType : Type?

Henrik Böving (Dec 28 2021 at 23:51):

No he means the newtype concept from haskell which is done in lean using a def or a one element structure

Henrik Böving (Dec 28 2021 at 23:54):

As an example, this is how ReaderT is defined in Lean:

def ReaderT (ρ : Type u) (m : Type u  Type v) (α : Type u) : Type (max u v) :=
  ρ  m α

@[inline] def ReaderT.run {ρ : Type u} {m : Type u  Type v} {α : Type u} (x : ReaderT ρ m α) (r : ρ) : m α :=
  x r

Vs haskell:

newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }

Pi Lanningham (Dec 28 2021 at 23:58):

So, thinking out loud here, if I wanted to define a type Hash as an alias for ByteArray, I could do

def Hash := ByteArray
structure Message where
  hash : Hash

Is there a Lean-idiomatic way to attach a proof to that? i.e. a hash is any byte array, so long as the size is 32 bytes or something along those lines?

Arthur Paulino (Dec 29 2021 at 00:03):

Then structure comes in handy:

structure Hash where
  data : ByteArray
  properLength : data.size = 32 := by simp

Henrik Böving (Dec 29 2021 at 00:03):

Okay multiple things:
First, there is a difference between an alias which would be an abbrev and a def, if you define a type using def it will not inherit the type class instances the type on the right hand side has automatically, if you define it with an abbrev it will.

now is there a Lean idiomatic way to attach a proof to that, yes there are actually multiple, first way would be to just have it as a structure field:

structure LenVec (α : Type u) (n : Nat) where
  list : List α
  len : list.length = n

second way would be using a subtype, example:

-- The rhs of this
def SortedBTree (α : Type u) (β : Type v) [LinearOrder α] : Type (max u v) := {t : BTree α β // Sorted t}

which of these two you pick in which situation I am actually not 100% sure about yet, especially since subtype is just:

structure Subtype {α : Sort u} (p : α  Prop) where
  val : α
  property : p val

I think if you just have value + property use a subtype, if you have more than one value or more than one property a structure with proofs might be better.

Pi Lanningham (Dec 29 2021 at 00:05):

Ooo, thank you! <3 That's super helpful, both of you

Arthur Paulino (Dec 29 2021 at 00:06):

The := by simp part of my example is serving as a default proof, if the user doesn't provide one when instantiating the structure

structure Hash where
  data : ByteArray
  properLength : data.size = 2 := by simp

def byteArray2 : ByteArray := #[3, 4]⟩
def byteArray3 : ByteArray := #[3, 4, 5]⟩

def h : Hash := Hash.mk byteArray2 -- works

def h' : Hash := Hash.mk byteArray3 -- breaks
-- unsolved goals
-- ⊢ False

Last updated: Dec 20 2023 at 11:08 UTC