Golf my iteration function

Here is my ungolfed Ruby code for a function I want to try and golf:

Iter =-> k {
str = ""
(0..k).map{|m| str += "-> f#{m} {"}
str += "f#{k}.times{f1 = f0[f1]};f1"
(2..k).map{|m| str += "[f#{m}]"}
eval(str + "}" * (k+1))
}


The best I can do to golf this is essentially shortening variable names, removing spaces, and rearranging the code to reduce the amount of loops:

I=->k{s="f#{k}.times{f1=f0[f1]};f1"
(2..k).map{|m|s+="[f#{m}]"}
(0..k).map{|m|s="->f#{k-m}{"+s+?}}
eval s}


Try it online!

This function can be compacted so that it avoids a lot of defining new functions. You can think of it like this:

$$\operatorname{Iter}(k;f_0,f_1,\dots,f_k)=f_0^{f_k}(f_1)(f_2)(f_3)\dots(f_k)$$

where

$$f^n(x)=\underbrace{f(f(\dots f(}_nx)\dots))$$

denotes function iteration. The types of arguments are given as:

$$\operatorname{Iter}(\text{int};\dots,(\text{int}\mapsto\text{int})\mapsto(\text{int}\mapsto\text{int}),\text{int}\mapsto\text{int},\text{int})$$

That is, the last argument is an integer, and each previous argument maps from T to T, where T is the type of the next argument on the right.

It is true that accepting all arguments at once would allow me to golf the above code further:

I=->k,*a{a[-1].times{a[1]=a[0][a[1]]};(2..k).map{|m|a[1]=a[1][a[m]]};a[1]}


However, the issue is that I need to curry this function. This way, I may treat objects such as

$$\operatorname{Iter}(k)(f_0)$$

as their own object, and thus be able to pass this into Iter(k) to get things such as

$$\operatorname{Iter}(k)(\operatorname{Iter}(k)(f_0))$$

As a specific example of what this function does, we have

\begin{align}\operatorname{Iter}(2)(\operatorname{Iter}(1))(x\mapsto x+1)(2)&=\operatorname{Iter}(1)(\operatorname{Iter}(1)(x\mapsto x+1))(2)\\&=\operatorname{Iter}(1)(x\mapsto x+1)(\operatorname{Iter}(1)(x\mapsto x+1)(2))\\&=\operatorname{Iter}(1)(x\mapsto x+1)(2+1+1)\\&=\operatorname{Iter}(1)(x\mapsto x+1)(4)\\&=4+1+1+1+1\\&=8\end{align}

I'm interested in seeing if this can be golfed down further, with the restriction that the arguments must be curried in the order provided.

• Mind if anyone explain the "unclear" close vote? I really did try my best to explain everything, so if there's any part that's unclear, just ask. Commented Jun 28, 2019 at 1:37
• It's a bit unclear because you have tagged this "tips", but it's written almost like a challenge. I'd remove the tips tag and make it more clearly a challenge. Otherwise, perhaps make it clear that you're looking for golfing tips for this specific program. Your last statement makes us unsure of what you want. Commented Jun 28, 2019 at 2:47
• Not sure if this is what you're looking for, but in J >: is the increment function, and your example I[2][I[1]][->x{x+1}][2] can be written >:^:2^:3 (2). Try it online!. ^: is the power of conjunction, and iteratively applies the verb on its left the number of times specified by the number on its right, with 1 being normal application f(x), 2 being f(f(x), etc. Commented Jun 28, 2019 at 6:17
• @lirtosiast Thanks and done Commented Jun 28, 2019 at 10:17
• @ValueInk that's not an infinite loop. The issue there is the end result is 3 times 2^402653191 (3<<402653191) Commented Jun 29, 2019 at 1:55

Ruby, 94 96 bytes

Using loops to do concatenations that followed such a simple pattern felt cumbersome, so I utilized the creative use of join instead, further golfed by the fact that array*str is equivalent to array.join(str)

+2 bytes to fix a typo I made that just so happened to return the same result on the test example by chance.

I=->k{eval"->f#{[*0..k]*'{->f'}{f#{k}.times{f1=f0[f1]};f1#{"[f#{[*2..k]*'][f'}]"if k>1}"+?}*-~k}


Try it online!

• Oh wow I never knew you could use array*str in Ruby, and like that! So much to learn... Commented Jun 28, 2019 at 22:31

Ruby, 87 bytes

I=->k{eval ("->f%d{"*-~k+"f%d.times{f1=f0[f1]};f1"+"[f%d]"*~-k+?}*-~k)%[*0..k,k,*2..k]}


Try it online!