One More Program and I'm Out!

21

1

Given a positive integer nesting level n and string s of printable ascii characters( to ~, output a program which, when run in the same language, outputs a program which outputs a program . . . which outputs the string s.

A total of n programs should be generated, all of which should be run in the same language as your answer.

Note: you may output programs or functions -- anything you are allowed by default as a submission.

You may input s with escaped characters, how a program or function in your language would usually input a string.


Example

For example, given n=1 and s="recursion", a Python 2 program might output:

print "recursion"

Running this would output:

recursion

Given n=2 and s="PPCG", a Python 2 program might output:

print "print \"PPCG\" "

Running this outputs:

print "PPCG"

Running this outputs:

PPCG

Related (+title inspiration): One more LUL and I'm out

Also Related (in sandbox - now deleted, but can still be viewed with enough reputation): Source Code Recursion

Test Cases

Make sure that your code works for the following test cases (one per line):

n s
2 PPCG
4 Robert'); DROP TABLE Students;--
17 Deep
2 Spaces In Here
3 "Don't forget quotes!"
5 'Backt`cks might be a h`tch'
6 5%s
8 [Brackets]<Are>(Great){Usually}
3 !"#$%&'()*+,-./ 0123456789:;<=>?@ABCDEFGHIJKLMN
6 OPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
7 THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
3 the quick brown fox jumps over the lazy dog

fireflame241

Posted 2017-09-27T22:34:53.053

Reputation: 7 021

1

Was reading the challenge and was like "hey, that looks very familiar..", and then noticed your "Also Related (in sandbox): Source Code Inspiration" to my Sandbox question. :) I'll leave my question there for now, but will delete it after a couple of weeks. Yours is basically the same, except with the addition of an integer parameter.

– Kevin Cruijssen – 2017-09-28T07:11:22.897

1As suggested here, is it allowed to return anonymous functions instead of programs? – Arnauld – 2017-09-28T09:07:18.760

1Does "positive integer" include 0? – Felix Palmen – 2017-09-28T09:16:57.673

1Did you choose program for a reason? The default is function or program? Is it allowed to have a function printing a function? – Kevin Cruijssen – 2017-09-28T11:48:45.860

Can we use escape characters in the input or must submissions handle inputs that are hard (possibly impossible in some languages) to parse? – Stewie Griffin – 2017-09-28T14:08:16.590

@Arnauld yes, an anonymous function may be output. – fireflame241 – 2017-09-28T14:28:42.740

@FelixPalmen No. Positive integer does not include 0, so you will never be asked to output s directly – fireflame241 – 2017-09-28T14:29:30.467

@StewieGriffin yes, escape characters may be used, such as inputting 'don\'t' in Python. – fireflame241 – 2017-09-28T14:31:48.307

Then those test cases doesn't make much sense. They seem to suggest the input format is very strict. Why else have all the "Don't forget quotes", "Back ticks might be a hitch", Little bobby tables and so on? – Stewie Griffin – 2017-09-28T14:33:32.337

1@StewieGriffin because escaping in sub-expressions or nested programs might be problematic (and someone asked for quote test cases in sandbox). – fireflame241 – 2017-09-28T14:41:26.393

1Is there any consensus on meta about that? The fact that a program or function is able to process a string including some special characters and the valid way(s) to pass it such a string properly are two completely independent issues, IMHO. String unescaping usually takes place at the tokenizer level exclusively and the final program is not even aware of that. Now, if a program really needs to receive, say, two raw backslashes instead of one, that would be indeed a problem. – Arnauld – 2017-09-28T15:12:35.170

"You may input s with escaped characters, however you would usually input a string." What does this mean? – Jakob – 2017-10-05T15:59:55.523

1@Jakob I think your confusion comes from "however" able to be used as a conjunction. Specified in question. – fireflame241 – 2017-10-05T22:41:58.130

Answers

19

Jelly, 2 bytes

Ṿ¡

Try it online!

Ṿ¡  Main link; left argument (text) is x, right argument (repetitions) is y
 ¡  Repeat y times:
Ṿ   Uneval x; produce code that outputs x

hehe builtins

HyperNeutrino

Posted 2017-09-27T22:34:53.053

Reputation: 26 575

This is broken, "hi" produces hi, not "hi" – Tahg – 2017-09-28T00:41:10.970

10@Tahg Jelly input is automatically evaluated as Python code if it doesn't throw an error. If it does, then it's just a string. You'd have to do '"hi"' to see the expected outcome – HyperNeutrino – 2017-09-28T00:42:25.097

19

JavaScript (ES6), 47 44 bytes

Saved 3 bytes thanks to @HermanLauenstein

Takes input in currying syntax (n)(s).

n=>g=s=>`alert(atob("${btoa(--n?g(s):s)}"))`

Example

f(2)('PPCG')

Will output:

'alert(atob("YWxlcnQoYXRvYigiVUZCRFJ3PT0iKSk="))'

Which will print:

'alert(atob("UFBDRw=="))'

Which will print:

'PPCG'

Demo

A more complex example where alert() has been overridden so that intermediate results are printed to the console and automatically executed.

let f =

n=>g=s=>`alert(atob("${btoa(--n?g(s):s)}"))`

alert = s => { console.log(s); try { eval(s); } catch(e) {} }

alert(f(5)("'Backt`cks might be a h`tch'"));


Alternate version, 40 bytes

Suggested by @Shaggy

This one returns an anonymous function instead of a full program.

n=>g=s=>`_=>atob("${btoa(--n?g(s):s)}")`

Arnauld

Posted 2017-09-27T22:34:53.053

Reputation: 111 334

Could you return an anonymous function, instead of using the alert? 41 bytes

– Shaggy – 2017-09-28T09:00:48.227

@Shaggy I don't really know. I've asked the OP. – Arnauld – 2017-09-28T09:08:10.043

If not, maybe you could get away with an IIFE instead for 45 bytes. – Shaggy – 2017-09-28T09:09:37.167

-3 bytes using currying: n=>g=s=>BTalert(atob("${btoa(--n?g(s):s)}"))BT (replace BT with backticks) – Herman L – 2017-09-28T17:41:59.183

@HermanLauenstein Thanks! :) – Arnauld – 2017-09-28T17:55:26.477

The same can be used in the alternate version: n=>g=s=>BT_=>atob("${btoa(--n?g(s):s)}")BT (replace BT with backticks – Herman L – 2017-09-28T18:03:49.567

10

sh + coreutils, 31 bytes

yes exec sed 1d \$0|sed $1q;cat

Takes n as a command-line parameter and s on STDIN.

Neil

Posted 2017-09-27T22:34:53.053

Reputation: 95 035

8This code says: "Yes, you definitely have to execute me." – RedClover – 2017-09-28T04:29:40.777

Can you add an explanation? I’m having trouble working it out – JoshRagem – 2017-09-28T14:07:28.233

1@JoshRagem yes repeatedly prints its command line, which is exec sed 1d $0 (the $ is a shell metacharacter so it has to be quoted). sed $1q stops printing after $1 (i.e. n) lines. cat then copies the input string. The resulting file is a sh script that tells the shell to replace itself with a copy of sed with the parameters 1d and the script's file name. sed then skips the first line of the file and outputs the rest. Each script has one fewer exec sed 1d $0 prefix, until after n executions only the original input is printed. – Neil – 2017-09-28T18:29:59.140

5

Python 2, 40 bytes

f=lambda r,t:r and"print%r"%f(r-1,t)or t

Try it online!

-4 bytes thanks to xnor

HyperNeutrino

Posted 2017-09-27T22:34:53.053

Reputation: 26 575

5

Haskell, 17 bytes

As of when I write this, this is the shortest answer for a non-golfing-specific language.

It is a function which takes s and n in that order, and returns the result or the source code of an expression which, when evaluated, returns the next source code.

(!!).iterate show

Argument for why this counts:

  1. Solutions are allowed to be functions.
  2. Their outputs are allowed to be functions.
  3. Those functions have no parameters.
  4. In Haskell, since it is lazy and everything-is-curried, the most natural — for practical programming purposes — definition of a 0-parameter function is the same as its result; the closest alternative, a 1-parameter function which ignores the parameter, is silly.

If f is given PPCG and 2 as its parameters, the result is the text "\"PPCG\"" (first generated function), which when evaluated returns the text "PPCG" (second generated funtion), and when that is evaluated it returns PPCG.

Thanks to nimi for suggesting a shortening.

Kevin Reid

Posted 2017-09-27T22:34:53.053

Reputation: 1 693

There is a relevant Meta question on the issue of functions with no arguments in Haskell, though it hasn't received that much attention yet and still has open questions: https://codegolf.meta.stackexchange.com/q/12924/56433

– Laikoni – 2017-09-29T06:48:55.743

3

APL (Dyalog), 24 23 bytes

-1 thanks to ngn.

This is a full program which prompts for s and then for n and prints to STDOUT.

''''{⍺,⍨⍺,⍵/⍨1+⍵=⍺}⍣⎕⊢⍞

Try it online! (the 17 Deep case is omitted as it exceeds TIO's output limit – works offline)

prompt for s

 yield that (to separate and )

''''{}⍣⎕ prompt for n and apply this lambda with a single quote as left argument that many times. stands for the left argument (the quote) and is stands for the right argument (the input text):

⍵=⍺ Boolean where the text is equal to a quote

1+ add one

⍵/⍨ replicate each character of the argument the corresponding number of times

⍺, prepend a quote

⍺,⍨ append a quote

This works because strings in APL are ' delimited and single-quotes in strings are doubled, while no other characters need escaping.


Dyalog APL also ships with a utility (⎕SE.Dyalog.Utils.repObj) that generates an APL expression which evaluates to its argument (similar to Jelly's uneval). The following program is therefore equivalent to the above, but works for all arrays:

⎕SE.Dyalog.Utils.repObj⍣⎕⊢⎕

Try it online!

Adám

Posted 2017-09-27T22:34:53.053

Reputation: 37 779

I think APLX allows "doubly-" as well as 'singly-quoted' strings. If the rest works there, you can save a byte :) ngn/apl used to but I removed "" recently – ngn – 2017-09-30T10:10:21.370

Consider passing the quote as .- that saves (at least) a byte. – ngn – 2017-09-30T10:16:44.083

@ngn Thanks, but APLX doesn't have dfns. NARS2000 has both double-quotes and and dfns, but characters cost two bytes each. – Adám – 2017-10-02T07:30:09.357

2

Java 8, 95 93 bytes

String c(String s,int n){return"v->\""+(n-->1?c(s,n).replaceAll("[\\\\\"]","\\\\$0"):s)+'"';}

-2 bytes thanks to @Lynn.

Escaping special characters is so annoying in Java..

Try it here and try the resulting method here.

Explanation:

String c(String s,int n){  // Method with String and int parameters and String return-type
  return"v->\""+           //  Return literal "v->" + a leading double-quote +
   (n-->1?                 //   If `n` is larger than 1:
     c(s,n)                //    Recursive-call,
      .replaceAll("[\\\\\"]","\\\\$0")
                           //    with all double-quotes ('"') and slashes ('\') escaped
    :                      //   Else:
     s)                    //    The input String
   +'"';                   //   + a trailing double quote
}                          // End of method 

Additional explanation for the regex replacement:

.replaceAll("[\\\\\"]","\\\\$0")
.replaceAll("        ","      ")  // Replace the match of the 1st String, with the 2nd
             [      ]             //  One of these inner characters:
              \\\\                //   Escaped slash ('\')
                  \"              //   Escaped double-quote ('"')
                                  //  And replace them with:
                        \\\\      //   Escaped slash ('\'),
                            $0    //   plus found match

Why all these slashes?

\   →  \\       // Escapes a single slash for the regex
\\  →  \\\\     // Escapes both regex-escaped slashes for the String
"   →  \"       // Escapes a double-quote for the String

Kevin Cruijssen

Posted 2017-09-27T22:34:53.053

Reputation: 67 575

1I don’t think you need to escape " in a regex character class, so \\\\\" (five backslashes) should be fine. – Lynn – 2017-09-28T16:10:01.940

2

Firefox JavaScript, 41 35 bytes

f=(s,n)=>"_=>"+uneval(--n?f(s,n):s)

Firefox has a nice uneval, which does what it sounds like - unevals a given object, in this case - string.

dzaima

Posted 2017-09-27T22:34:53.053

Reputation: 19 048

2

Underload, 11 bytes

(a(S)*)~^^S

Try it online!

Input needs to start on the stack, with the number on top in the form of a church numeral. I don't know if this is a valid input method, but the specification has no input, and placing input to the top of the stack seems like a stranded method used in such languages.

MegaTom

Posted 2017-09-27T22:34:53.053

Reputation: 3 787

1

GolfScript, 5 bytes

~{`}*

Try it online!

Erik the Outgolfer

Posted 2017-09-27T22:34:53.053

Reputation: 38 134

1

QuadR, 8 bytes

Simple translation of ngn's answer.

Takes n as argument and s as Input.

^|'|$
'&

Try it online!

PCRE Replace all instances of

^|'|$ Beginning of line OR Quote OR End of line

'& with a Quote and the entire match

The Argument specifies how many times to repeat the transformation.

Adám

Posted 2017-09-27T22:34:53.053

Reputation: 37 779

ah, now I know what that language is for :) – ngn – 2017-10-02T17:47:34.630

1

R, 62 bytes

f=function(n,s){"if"(n,{formals(f)$n=n-1;formals(f)$s=s;f},s)}

Try it online!

Call it like so: f(n,s) followed by n copies of ()

A named function; returns an anonymous function. All it does is modify the default values of the formals of f, allowing the resulting function to be called (and then the result of that called, n times). when n reaches 0, it returns s.

R is actually not too bad at escaping! It uses C-style escaping, so you just have to take the input, replace " with \" and \ with \\, and then wrap the whole thing in " ".

Giuseppe

Posted 2017-09-27T22:34:53.053

Reputation: 21 077

0

Pyth, 21 bytes

L++NsXbJ,N\\+L\\JNyFz

Try it here.

Unfortunately the recursive function (not full program as above) is longer (24 bytes):

M?GgtG++NsXHJ,N\\+L\\JNH

Erik the Outgolfer

Posted 2017-09-27T22:34:53.053

Reputation: 38 134

0

APL (Dyalog Classic), 19 bytes

'^|''|$'⎕r'''&'⍣⎕⊢⍞

Try it online!

ngn

Posted 2017-09-27T22:34:53.053

Reputation: 11 449

That's very clever. I tried this approach, but didn't think of prepending. – Adám – 2017-10-02T07:09:35.290

Sell also this.

– Adám – 2017-10-02T07:17:25.647

0

Ruby, 34 bytes

%p is a Ruby-specific printf flag that gets the inspect value of its argument, similar to %r in Python. $><< means print.

f=->n,s{"$><<%p"%(n>1?f[n-1,s]:s)}

Try it online!

Value Ink

Posted 2017-09-27T22:34:53.053

Reputation: 10 608

0

Excel VBA (32-Bit), 67 Bytes

Version Restricted to 32-Bit Excel VBA because 2^i evaluates without error in 32-Bit VBA, but not in 64-Bit VBA

Anonymous VBE immediate window function that takes inputs n and s from from ranges [A1] and [B1] and outputs an anonymous function that when evaluated down to only a terminal (after n iterations) outputs only s as that terminal

For i=0To[A1-1]:q=q+"?"+String(2^i,34):Next:?q[B1]Replace(q,"?","")

Sample Input / Output

[A1:B1]=Array(7, "PPCG")
For i=0To[A1-1]:q=q+"?"+String(2^i,34):Next:?q[B1]Replace(q,"?","")
?"?""?""""?""""""""?""""""""""""""""?""""""""""""""""""""""""""""""""?""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""PPCG"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
?"?""?""""?""""""""?""""""""""""""""?""""""""""""""""""""""""""""""""PPCG"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
?"?""?""""?""""""""?""""""""""""""""PPCG"""""""""""""""""""""""""""""""
?"?""?""""?""""""""PPCG"""""""""""""""
?"?""?""""PPCG"""""""
?"?""PPCG"""
?"PPCG"
PPCG

Taylor Scott

Posted 2017-09-27T22:34:53.053

Reputation: 6 709