5
\$\begingroup\$

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.

\$\endgroup\$
11
  • \$\begingroup\$ 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. \$\endgroup\$ Jun 28, 2019 at 1:37
  • 1
    \$\begingroup\$ 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. \$\endgroup\$
    – mbomb007
    Jun 28, 2019 at 2:47
  • 1
    \$\begingroup\$ 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. \$\endgroup\$
    – Jonah
    Jun 28, 2019 at 6:17
  • 1
    \$\begingroup\$ @lirtosiast Thanks and done \$\endgroup\$ Jun 28, 2019 at 10:17
  • 1
    \$\begingroup\$ @ValueInk that's not an infinite loop. The issue there is the end result is 3 times 2^402653191 (3<<402653191) \$\endgroup\$ Jun 29, 2019 at 1:55

2 Answers 2

3
\$\begingroup\$

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!

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

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!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.