Zulip Chat Archive

Stream: new members

Topic: recursive let in


Anatole Dedecker (Sep 09 2020 at 11:51):

Programming question here. Is there some way to define a recursive function using a let ... in expression ? Here's an example in Haskell, which I don't manage to translate to Lean :

fac n =
  let
    aux 0 acc = acc
    aux n acc = aux (n-1) (n*acc)
  in
  aux n 1

Reid Barton (Sep 09 2020 at 12:02):

No, I think you have to float aux out to a top-level function if you want to use the equation compiler. Alternatively you could use the recursor directly (either in term mode or in tactic mode).

Anatole Dedecker (Sep 09 2020 at 12:03):

Ok, thanks !

Anatole Dedecker (Sep 09 2020 at 12:09):

Actually, we can even use tactic mode :sweat_smile:

def fac (n : ) :=
  let aux :      :=
    begin
      intros k,
      induction k with k hk,
      { exact id },
      { intros acc,
        exact hk ((k+1) * acc) }
    end
  in aux n 1

Kevin Buzzard (Sep 09 2020 at 12:12):

can you prove anything about it though?

Kevin Buzzard (Sep 09 2020 at 12:12):

I am a bit scared about the proof term which induction gives you...

Anatole Dedecker (Sep 09 2020 at 12:13):

It looks okay actually. And at least it evaluates correctly

Reid Barton (Sep 09 2020 at 12:14):

If you want to prove things about it then it's probably better to float it to top-level

Anatole Dedecker (Sep 09 2020 at 12:14):

Indeed !

Kevin Buzzard (Sep 09 2020 at 12:14):

can you prove (n+1)!=(n+1)*n! using your definition?

Anatole Dedecker (Sep 09 2020 at 13:09):

Oh that's quite annoying indeed...

Chris Wong (Sep 10 2020 at 12:20):

Is hk just the identity function here? Trying to wrap my head around what that induction is doing...

Eric Wieser (Sep 10 2020 at 13:56):

@Kevin Buzzard, I was able to prove it with

lemma rec_succ {C:   Type} {zero_f : C 0} {succ_f : Π n, C n  C n.succ} (n : ) :
  @nat.rec C zero_f succ_f (n + 1) = succ_f n (@nat.rec C zero_f succ_f n) := rfl

example (n : ) : fac (n + 1) = (n+1)*(fac n) := begin
  dsimp only [fac],
  conv_lhs {
    rw (rec_succ n),
    rw mul_one,
  },
  generalize : n + 1 = m,
  induction n with n' generalizing m,
  { simp, },
  {
    conv_lhs { rw n_ih},
    conv_rhs { rw n_ih},
    ring,
  }
end

Although I feel like rec_succ should be builtin somewhere

Eric Wieser (Sep 10 2020 at 14:24):

Ah, dsimp can handle it after a nat.add_one:

example (n : ) : fac (n + 1) = (n+1)*(fac n) := begin
  rw nat.add_one n,
  dsimp only [fac],
  rw [mul_one, nat.add_one n],
  generalize : n.succ = m,
  induction n with n' generalizing m,
  { simp, },
  { conv_lhs { rw n_ih }, conv_rhs { rw n_ih }, ring, }
end

Last updated: Dec 20 2023 at 11:08 UTC