\$\begingroup\$@ATaco Unfortunately yes. Other languages, such as lisp, have the syntax structured in such a way that making a useful pristine program is impossible.\$\endgroup\$
– ShelvacuJul 11 '17 at 5:28

which works by concatenating the data string with a quoted version (by using show) of itself and printing the result. However, this is not pristine as any characters in the data string can be removed without failing and also the $(++)<*>show$ or (++)<*> part could be dropped without the program breaking.

To fix this, a custom print function q is defined which checks the length of the given string and calls fail if it's shorter than 132. This catches the removing of any sequence from the data string and also the removals of $(++)<*>show$ or (++)<*>, as in both cases the resulting string passed to q is shorter.

In q the number 132 could be shortened to 1, 13, 32 or 2, but in each case again fail is called.

As far as I can tell, the removal of any other substring causes either an syntax or type error, so the program does not even compile in the first place. (Haskell's strict type system comes in handy here.)

\$\begingroup\$@ØrjanJohansen Good catch, I had an if then else before but thought I could shorten it.\$\endgroup\$
– LaikoniJul 11 '17 at 15:51

2

\$\begingroup\$putStr x can become p x, which when I tried on my system ran for a very long time before I killed it, I suspect the tail call recursion was optimized, so it's an infinite loop. I don't know enough haskell to give any suggestions on how to fix it.\$\endgroup\$
– ShelvacuJul 12 '17 at 8:35

How it works

We can’t easily use multiple statements since the second one could be deleted, so we start with a single-expression quine:

print((lambda s:s%s)('print((lambda s:s%%s)(%r))'))

To protect it against substring deletions, we use open(1,"w").write instead of print. In Python 3, write returns the number of written characters, which we will verify is 113 to ensure that no part of the string was deleted. We do this by looking up the return value in the dictionary {113:[]}, and looping over the result with for[]in…:a, which will fail if we didn’t get an empty iterable or if the for statement is deleted.

For MLton, full SML programs are either expressions delimited and terminated by ; (e.g. print"Hello";print"World";) or declarations with the var and fun keywords (e.g. var _=print"Hello"var _=print"World") where _ is a wild card which could also be replaced by any variable name.

The first option is useless for pristine programming because ; on its own is a valid program (which does nothing, but doesn't error either). The problem with the second approach is that declarations like var _=print"Hello" can be shortened to just var _="Hello" (or even var _=print) because the declaration with var works as long as the right-hand side is a valid SML expression or value (SML is a functional language, so functions can be used as values too).

At this point, I was ready to declare pristine programming in SML impossible, when by chance I stumbled upon pattern matching in val-declarations. It turns out that the syntax for declarations is not val <variable_name> = <expression> but val <pattern> = <expression>, where a pattern can consist of variable names, constants and constructors. As the print function has type string -> unit, we can use a pattern match on the unit-value () to enforce that the print function is actually applied to the string: val()=print"Hey". With this approach, removing either print or "Hey" results in a Pattern and expression disagree-error.

With this way of pristine printing at hand, the next step is to write a quine, before finally some more save-guarding needs to be added. I previously used an easy SML quine technique (see the revision history), but Anders Kaseorg pointed out a different approach which can save some bytes in his case. It uses the built-in String.toString function to handle string escaping and is of the general form <code>"<data>", where "<data>" is an escaped string of the code before:

This is a working quine but not yet pristine. First of all Anders Kaseorg found out that MLton accepts a single quote " as code without producing errors, which means we cannot have code ending in a quote as above. The shortest way to prevent this would be to wrap everything after val()= in a pair of parenthesis, however then the code could be reduced to val()=(). The second shortest way I found is to use val()=hd[ ... ], that is we wrap everything into a list and return its first element to make the type checker happy.

To make sure that no part of the data string can be removed without being noticed, the pattern-matching in val-declarations comes in handy again: The length of the final string to be printed (and thus the program length) should equal 195, so we can write let val t=... val 195=size t in print t end in the body of the fn abstraction instead of print(...). Removing a part of the string results in a length less than 189, thus causing a Bind exception to be thrown.

There is still an issue left: the whole val 195=size t check could simply be dropped. We can prevent this by expanding the check to match on a tuple: val t=... val(216,u)=(n+size t,t)in print u end, such that removing the check results in an unbound variable u.

\$\begingroup\$@AndersKaseorg Huh, that's strange. However it should be possible to fix this issue by using another let ... in ... end.\$\endgroup\$
– LaikoniJan 3 '18 at 14:33

\$\begingroup\$@AndersKaseorg I fixed the issue, hopefully without introducing new "vulnerabilities".\$\endgroup\$
– LaikoniJan 4 '18 at 18:42

\$\begingroup\$Actually I looked into MLton accepting " as a program, and it seems that bug was fixed in this commit, so maybe your 182 or my 180 is fine as long as you specify the unreleased Git version of MLton.\$\endgroup\$
– Anders KaseorgJan 4 '18 at 19:33

Ruby, 78 bytes

I wrote this when I thought of the challenge to make sure it was possible. It uses the same "wrapper" from one of my answers to the original pristine challenge.

Explanation:

eval(*[expr])

This evaluates whatever code returns as a ruby program. This effectively tests that the string that code returns is a valid ruby program. Conveniently, ruby programs can be blank, or only consist of whitespace.

The "splat" operator * allows you to use an array as arguments to a function. This also means that if eval is removed, the resulting program is (*[expr]), which is not valid ruby.

($>.write(str)-78).chr

$> is a short variable for STDOUT.

$>.write(foo) writes foo to STDOUT and, importantly for this code, returns the number of bytes written.

$>.write(foo)-78: Here 78 is the length of the program, and so if the program is not mangled, will also be the number of bytes written. Therefor, in the unmangled case, this will return zero.

num.chr returns num as a character, eg 0.chr will return a string containing a single null byte. In the unmangled program, this will give a string with a single null byte to eval, which is a valid ruby program that is a no-op.

Also, the program can have a substring removed such that it's just eval(*[(78).chr]) or eval(*[(8).chr]), which means that the numeric constant cannot end with any of the numbers (0, 4, 9, 10, 11, 12, 13, 26, 32, 35, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 59, 64, 95) because they are ascii codes for valid single-character ruby programs.

%{ str }

This is a lesser-known syntax for string literals in ruby. The reason it's used here is that balanced pairs of {} can be used within the string, which means this syntax can contain itself. For example, %{foo{bar}} is the same as "foo{bar}".

(s=%{data})%s

This defines the variable s which is the data of this quine, as a printf string.

Assignments in ruby return what was assigned, so this is the same as first assigning s and then running s%s

% on a string is syntatic sugar for ruby's equivalent of sprintf. The %s signifies where within the data the data itself should be embedded.

This bit of code defines the data portion of the quine and embeds it within itself to create the full code.

Your Answer

If this is an answer to a challenge…

…Be sure to follow the challenge specification. However, please refrain from exploiting obvious loopholes. Answers abusing any of the standard loopholes are considered invalid. If you think a specification is unclear or underspecified, comment on the question instead.

…Try to optimize your score. For instance, answers to code-golf challenges should attempt to be as short as possible. You can always include a readable version of the code in addition to the competitive one.
Explanations of your answer make it more interesting to read and are very much encouraged.

…Include a short header which indicates the language(s) of your code and its score, as defined by the challenge.

More generally…

…Please make sure to answer the question and provide sufficient detail.

…Avoid asking for help, clarification or responding to other answers (use comments instead).