23
\$\begingroup\$

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
\$\endgroup\$
13
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ Commented Sep 28, 2017 at 7:11
  • 1
    \$\begingroup\$ As suggested here, is it allowed to return anonymous functions instead of programs? \$\endgroup\$
    – Arnauld
    Commented Sep 28, 2017 at 9:07
  • 1
    \$\begingroup\$ Does "positive integer" include 0? \$\endgroup\$ Commented Sep 28, 2017 at 9:16
  • 1
    \$\begingroup\$ Did you choose program for a reason? The default is function or program? Is it allowed to have a function printing a function? \$\endgroup\$ Commented Sep 28, 2017 at 11:48
  • 1
    \$\begingroup\$ @StewieGriffin because escaping in sub-expressions or nested programs might be problematic (and someone asked for quote test cases in sandbox). \$\endgroup\$ Commented Sep 28, 2017 at 14:41

17 Answers 17

19
\$\begingroup\$

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

\$\endgroup\$
2
  • \$\begingroup\$ This is broken, "hi" produces hi, not "hi" \$\endgroup\$
    – Tahg
    Commented Sep 28, 2017 at 0:41
  • 11
    \$\begingroup\$ @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 \$\endgroup\$
    – hyperneutrino
    Commented Sep 28, 2017 at 0:42
19
\$\begingroup\$

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)}")`
\$\endgroup\$
6
  • \$\begingroup\$ Could you return an anonymous function, instead of using the alert? 41 bytes \$\endgroup\$
    – Shaggy
    Commented Sep 28, 2017 at 9:00
  • \$\begingroup\$ @Shaggy I don't really know. I've asked the OP. \$\endgroup\$
    – Arnauld
    Commented Sep 28, 2017 at 9:08
  • \$\begingroup\$ If not, maybe you could get away with an IIFE instead for 45 bytes. \$\endgroup\$
    – Shaggy
    Commented Sep 28, 2017 at 9:09
  • \$\begingroup\$ -3 bytes using currying: n=>g=s=>BTalert(atob("${btoa(--n?g(s):s)}"))BT (replace BT with backticks) \$\endgroup\$
    – Endenite
    Commented Sep 28, 2017 at 17:41
  • \$\begingroup\$ @HermanLauenstein Thanks! :) \$\endgroup\$
    – Arnauld
    Commented Sep 28, 2017 at 17:55
10
\$\begingroup\$

sh + coreutils, 31 bytes

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

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

\$\endgroup\$
3
  • 9
    \$\begingroup\$ This code says: "Yes, you definitely have to execute me." \$\endgroup\$
    – RedClover
    Commented Sep 28, 2017 at 4:29
  • \$\begingroup\$ Can you add an explanation? I’m having trouble working it out \$\endgroup\$
    – JoshRagem
    Commented Sep 28, 2017 at 14:07
  • 1
    \$\begingroup\$ @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. \$\endgroup\$
    – Neil
    Commented Sep 28, 2017 at 18:29
5
\$\begingroup\$

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

\$\endgroup\$
0
5
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\begingroup\$ 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: codegolf.meta.stackexchange.com/q/12924/56433 \$\endgroup\$
    – Laikoni
    Commented Sep 29, 2017 at 6:48
3
\$\begingroup\$

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!

\$\endgroup\$
3
  • \$\begingroup\$ 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 \$\endgroup\$
    – ngn
    Commented Sep 30, 2017 at 10:10
  • \$\begingroup\$ Consider passing the quote as .- that saves (at least) a byte. \$\endgroup\$
    – ngn
    Commented Sep 30, 2017 at 10:16
  • \$\begingroup\$ @ngn Thanks, but APLX doesn't have dfns. NARS2000 has both double-quotes and and dfns, but characters cost two bytes each. \$\endgroup\$
    – Adám
    Commented Oct 2, 2017 at 7:30
2
\$\begingroup\$

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.

\$\endgroup\$
2
\$\begingroup\$

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
\$\endgroup\$
1
  • 1
    \$\begingroup\$ I don’t think you need to escape " in a regex character class, so \\\\\" (five backslashes) should be fine. \$\endgroup\$
    – lynn
    Commented Sep 28, 2017 at 16:10
2
\$\begingroup\$

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.

\$\endgroup\$
2
\$\begingroup\$

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 " ".

\$\endgroup\$
1
\$\begingroup\$

GolfScript, 5 bytes

~{`}*

Try it online!

\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\begingroup\$ ah, now I know what that language is for :) \$\endgroup\$
    – ngn
    Commented Oct 2, 2017 at 17:47
1
\$\begingroup\$

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
\$\endgroup\$
1
\$\begingroup\$

Vyxal, 2 bytes

(q

Try it Online!

N times, uneval the string.

\$\endgroup\$
0
\$\begingroup\$

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
\$\endgroup\$
0
\$\begingroup\$

APL (Dyalog Classic), 19 bytes

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

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ That's very clever. I tried this approach, but didn't think of prepending. \$\endgroup\$
    – Adám
    Commented Oct 2, 2017 at 7:09
  • \$\begingroup\$ Sell also this. \$\endgroup\$
    – Adám
    Commented Oct 2, 2017 at 7:17
0
\$\begingroup\$

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!

\$\endgroup\$

Your Answer

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

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