Haskell, 306 + 624 = 930 bytes
Program 1: An anonymous function taking a dummy argument and returning a string.
(\b c()->foldr(\a->map pred)b(show()>>c)`mappend`show(map(map fromEnum)$tail(show c):pure b))"İĴİóđđđÝöÝâÝæÝääē××êääē××İēÀħđĮâħēĕóİóòòĮááħááđéêâéêēááĮÀħ""(\b c()->foldr(\a->map pred)b(show()>>c)`mappend`show(map(map fromEnum)$tail(show c):pure b))"
Try it online!
q[[40,...]] at the end is an anonymous function taking a dummy argument and returning a string.
Try it online!
Character set 1 (includes space):
Character set 2 (includes newline):
Since only set 1 contains non-ASCII characters, their UTF-8 bytes are also disjoint.
How it works
Program 1 is generally written with lambda expressions, spaces and parentheses, free use of builtin alphanumeric functions, and with the quine data as string literals at the end.
- Program 1's own core code is turned into string literal data simply by surrounding it with quote marks.
- To support this, every backslash is followed by
b, which form valid escape sequences that roundtrip through
- Another tiny benefit is that
c are the only lower case letters whose ASCII codes are less than 100, saving a digit in the numerical encoding used by program 2.
- The string literal encoding of program 2's core code is more obfuscated by using non-ASCII Unicode: Every character has 182 added to its code point to ensure there is no overlap with the original characters.
- 182 used to be 128, until I realized I could abuse the fact that 182 is twice the length of the string literal for program 1's code to shorten the decoding. (As a bonus, program 2 can use newlines.)
Program 2 is generally written with top level function equations (except for the final anonymous one), character literals and decimal numbers, list/range syntax and operators, and with the quine data as a list of lists of
Ints at the end.
- Program 1's core code is encoded as a list of its code points, with a final double quote.
- Program 2's core code is encoded as the list of code points of the string literal used in program 1, still shifted upwards by 182.
Walkthrough, program 1
c are the values of the string literals for program 2 and 1, respectively, given as final arguments to the lambda expression.
() is a dummy argument solely to satisfy PPCG's rule that the program should define a function.
foldr(\a->map pred)b(show()>>c) decodes the string
b to the core code of program 2 by applying
map pred to it a number of times equal to the length of
show()>>c == c++c, or
tail(show c) converts the string
c to the core code of program 1, with a final double quote appended.
:pure b combines this in a list with the string
map(map fromEnum)$ converts the strings to lists of code points.
`mappend`show(...) serializes the resulting list of lists and finally appends it to the core code of program 2.
Walkthrough, program 2
- The toplevel
z~z=[[['@','0'..]!!4..]!!z] is a function converting code points back to characters (necessary to write since not all the characters in
toEnum are available.)
- Its code point argument is also called
z. The laziness marker
~ has no effect in this position but avoids a space character.
['@','0'..] is a backwards stepping list range starting at ASCII code 64, then jumping 16 down each step.
!!4 to this gives a
- Wrapping that in a
[ ..] range gives a list of all characters, which
- The character is finally wrapped in a singleton list. This allows mapping the function
z over lists using
=<< instead of the unavailable
- The toplevel
q[x,q]_=z=<<x++q++[34,34]++x is a function constructing program 1 from the quine data list.
x is the data for the core of program 1 (including a final double quote) and the inner
q is the obfuscated data for the core of program 2.
_ is another dummy argument solely to make the final anonymous function a function instead of just a string.
x++q++[34,34]++x concatenates the pieces, including two double quote marks with ASCII code 34.
z=<< constructs program 1 by mapping
z over the concatenation to convert from code points to characters.
- The final
q[[40,...]] is an anonymous function combining
q with the quine data.