Zulip Chat Archive

Stream: Is there code for X?

Topic: Generate curried function based on list?


aron (Mar 19 2025 at 20:13):

I'm trying to write a function that can convert a function that takes a list as input into a curried function. Something like this:

def makeCurriedType (t T : Type u) (n : Nat) : Type u :=
  if n = 0 then T else t  makeCurriedType t T (n - 1)


def convertToCurriedType {t T : Type u} (n : Nat) (f : List t  T) : makeCurriedType t T n :=
  let rec recursor (args : List t) (paramsRemaining : Nat) : makeCurriedType t T paramsRemaining :=
    match h : paramsRemaining with
    | 0 =>
      by
      have result := f args
      simp
      exact result

    | n + 1 =>
      by
      have nextFun := fun head => recursor (head :: args) n
      have : makeCurriedType t T (n + 1) = (t  makeCurriedType t T n) := by
        induction n with
        | zero =>
          simp
        | succ n hh =>
          simp at h
          rw [h] at hh
          sorry

      rw [this]
      exact nextFun

  recursor [] n

but I can't quite make it work. In particular I don't understand why hh is a function whose first parameter needs to be a proof that paramsRemaining = n.succ? Especially since that's impossible, since h : paramsRemaining = (n + 1).succ

aron (Mar 19 2025 at 20:16):

But to be honest I'd rather not use induction in the first place. Which I could do if there was a way for me to simp just one single recursive call of makeCurriedType. Then I could show that

makeCurriedType t T (n + 1) = (t  makeCurriedType t T n)

by definition.

Is there a way to do this? Unroll just one iteration of a recursive function?

Eric Wieser (Mar 19 2025 at 20:29):

makeCurriedType is docs#Function.OfArity

aron (Mar 19 2025 at 20:33):

ah nice. but the problem isn't with that, it's with convertToCurriedType

Ilmārs Cīrulis (Mar 19 2025 at 20:38):

I took liberty to redefine makeCurriedType. It seems that everything works that way.

import Mathlib

def makeCurriedType (t T : Type u) (n : Nat) : Type u :=
  match n with
  | 0 => T
  | m + 1 => t  makeCurriedType t T m

def convertToCurriedType {t T : Type u} (n : Nat) (f : List t  T) : makeCurriedType t T n :=
  let rec recursor (args : List t) (paramsRemaining : Nat) : makeCurriedType t T paramsRemaining :=
    match h : paramsRemaining with
    | 0 =>
      by
      have result := f args
      exact result
    | n + 1 =>
      by
      have nextFun := fun head => recursor (head :: args) n
      have : makeCurriedType t T (n + 1) = (t  makeCurriedType t T n) := by
        induction n with
        | zero =>
          simp
          rfl
        | succ n hh =>
          simp at h
          rw [h] at hh
          rfl
      rw [this]
      exact nextFun
  recursor [] n

Eric Wieser (Mar 19 2025 at 20:56):

I think you're overthinking this:

def convertToCurriedType {t T : Type u} (n : Nat) (f : List t  T) : Function.OfArity t T n :=
  match n with
  | 0 => f []
  | n + 1 => fun x => convertToCurriedType n (f <| x :: ·)

Eric Wieser (Mar 19 2025 at 20:57):

@Ilmārs Cīrulis is right that redefining makeCurriedType makes things easier, and indeed the new definition they use is now equal to the one OfArity produces

Eric Wieser (Mar 19 2025 at 21:02):

Though you can get there in even less code with

def convertToCurriedType {t T : Type u} (n : Nat) (f : List t  T) : Function.OfArity t T n :=
  Function.OfArity.curry fun args => f (.ofFn args)

aron (Mar 19 2025 at 21:06):

@Ilmārs Cīrulis oh nice. In fact if I use your definition of makeCurriedType things can be made even simpler:

def makeCurriedType (t T : Type u) (n : Nat) : Type u :=
  match n with
  | 0 => T
  | m + 1 => t  makeCurriedType t T m

def convertToCurriedType {t T : Type u} (n : Nat) (f : List t  T) : makeCurriedType t T n :=
  let rec recursor (args : List t) (paramsRemaining : Nat) : makeCurriedType t T paramsRemaining :=
    match paramsRemaining with
    | 0 => f args
    | n + 1 => fun head => recursor (head :: args) n

  recursor [] n

Why does that work when my original definition of makeCurriedType didn't? :thinking: is it because my definition didn't make it clear that the function terminates?

Aaron Liu (Mar 19 2025 at 21:13):

I'm thinking it might be because your original definition uses well-founded recursion

Eric Wieser (Mar 19 2025 at 21:13):

And probably also because n + 1 - 1 = n is not true by definition Nevermind, it is!


Last updated: May 02 2025 at 03:31 UTC