Zulip Chat Archive

Stream: lean4

Topic: Definition Macro?


Joseph O (May 19 2022 at 18:52):

How could I make a macro in Lean such that

(define (add [x Nat] [y Nat]) (x + y))

expands into

def add (x : Nat) (y : Nat) := x + y

Arthur Paulino (May 19 2022 at 20:10):

syntax binder := "[" ident term "]"
syntax "(" "define" "(" ident binder* ")" term " : " term ")" : command

macro_rules
  | `((define ($f:ident [$nm:ident $ty:term]) $v:term : $ty':term)) =>
    `(def $f:ident : $ty  $ty' := fun $nm => $v:term)
  | `((define ($f:ident [$nm:ident $ty:term] $bs:binder*) $v:term : $ty':term)) =>
    `((define ($f:ident $bs:binder*) fun $nm => $v:term : $ty  $ty':term))

(define (add [x Nat] [y Nat]) x : Nat)

#eval add 3 5 -- 5

Arthur Paulino (May 19 2022 at 20:14):

Here's a fun idea:

syntax binder := "[" ident term "]"
syntax "(" "define" "(" "[" ident term "]" binder* ")" term ")" : command

macro_rules
  | `((define ([$f:ident $ty':term] [$nm:ident $ty:term]) $v:term)) =>
    `(def $f:ident : $ty:term  $ty':term := fun $nm:ident => $v:term)
  | `((define ([$f:ident $ty':term] [$nm:ident $ty:term] $bs:binder*) $v:term)) =>
    `((define ([$f:ident $ty:term  $ty':term] $bs:binder*) fun $nm => $v:term))

(define ([add Nat] [x Nat] [y Nat]) x)

#eval add 3 5 -- 5

Joseph O (May 19 2022 at 20:30):

Thanks!

Arthur Paulino (May 19 2022 at 20:31):

There's something wrong with my code tho

Arthur Paulino (May 19 2022 at 20:34):

(define ([add Nat] [x Nat] [bla Int]) x)

#eval add 3 5 -- 5

I would expect that to eval to 3, but it's being evaluated to 5. Maybe someone else might be able to help you

Joseph O (May 19 2022 at 20:57):

@Arthur Paulino I think its because the arguments are reversed

Notification Bot (May 20 2022 at 13:10):

Joseph O has marked this topic as unresolved.

Joseph O (May 20 2022 at 13:10):

Hm can someone explain this weird behavior?
image.png
image.png

Arthur Paulino (May 20 2022 at 13:11):

I can't understand what's wrong with those screenshots

Joseph O (May 20 2022 at 13:12):

For more context, here is test3

def test3 : List Nat :=
  let x := [1, 2], y := [3, 4] in x ++ y

Arthur Paulino (May 20 2022 at 13:13):

I believe you posted on the wrong thread

Joseph O (May 20 2022 at 13:14):

Arthur Paulino said:

I believe you posted on the wrong thread

I don't think so, because this has something to do with the definition macro

Joseph O (May 20 2022 at 13:15):

As when it is uncommented (the add function), it breaks test3

Arthur Paulino (May 20 2022 at 13:15):

#mwe please

Joseph O (May 20 2022 at 13:34):

Arthur Paulino said:

#mwe please

syntax binder := ident " := " term
syntax "let" binder,+ " in " term : term

macro_rules
  | `(let $name:ident := $v:term in $t:term) => `(let $name := $v; $t)
  | `(let $name:ident := $v:term, $bs:binder,* in $t:term) =>
    `(let $name := $v; let $bs:binder,* in $t:term)

syntax binder := "[" ident term "]"
syntax "(" "define" "(" binder+ ")" term ")" : command

macro_rules
  | `((define ([$f:ident $ty':term] [$nm:ident $ty:term]) $v:term)) =>
    `(def $f:ident : $ty:term  $ty':term := fun $nm:ident => $v:term)
  | `((define ([$f:ident $ty':term] [$nm:ident $ty:term] $bs:binder*) $v:term)) =>
    `((define ([$f:ident $ty:term  $ty':term] $bs:binder*) fun $nm => $v:term))

def test3 : List Nat :=
  let x := [1, 2], y := [3, 4] in x ++ y

#eval test3 -- [1, 2, 3, 4]

-- try commenting and uncommenting this line, and see what happens to the eval
(define ([add Nat] [x Nat] [y Nat]) x + y)

Arthur Paulino (May 20 2022 at 13:38):

There's a conflict with the declaration of binder

Joseph O (May 20 2022 at 13:38):

Arthur Paulino said:

There's a conflict with the declaration of binder

Oh I see

Joseph O (May 20 2022 at 13:40):

I renamed them and I still get the same error

Raghuram (May 20 2022 at 13:47):

Joseph O said:

Hm can someone explain this weird behavior?
image.png
image.png

I got similar errors. I think Lean is interpreting (define ...) as a term to which test3 is applied. See if the error goes away if you put section end between the #eval and (define ...).
As for how to make (define ...) recognised as a separate command, I don't know.

Raghuram (May 20 2022 at 13:48):

Wait; are you not getting any errors on the (define ...) line when it's uncommented? That's different from what I got.

Arthur Paulino (May 20 2022 at 13:51):

Apparently the parens from (define ⋯ is causing the confusion. This works:

syntax binder := ident " := " term
syntax "let " binder,+ " in " term : term

macro_rules
  | `(let $name:ident := $v:term in $t:term) => `(let $name := $v; $t)
  | `(let $name:ident := $v:term, $bs:binder,* in $t:term) =>
    `(let $name := $v; let $bs:binder,* in $t:term)

syntax binder' := "[" ident term "]"
syntax "⦃" "define" "(" binder'+ ")" term "⦄" : command

macro_rules
  | `(⦃define ([$f:ident $ty':term] [$nm:ident $ty:term]) $v:term⦄) =>
    `(def $f:ident : $ty:term  $ty':term := fun $nm:ident => $v:term)
  | `(⦃define ([$f:ident $ty':term] [$nm:ident $ty:term] $bs:binder'*) $v:term⦄) =>
    `(⦃define ([$f:ident $ty:term  $ty':term] $bs:binder'*) fun $nm => $v:term⦄)

def test3 : List Nat :=
  let x := [1, 2], y := [3, 4] in x ++ y

#eval test3 -- [1, 2, 3, 4] works

define ([add Nat] [x Nat] [y Nat]) x + y -- works

Last updated: Dec 20 2023 at 11:08 UTC