Haskell, 3 quines, 1119 bytes
Quine 1, 51 bytes
An anonymous IO
action printing directly to stdout.
putStr`mappend`print`id`"putStr`mappend`print`id`"
Try it online!
Quine 2, 265 bytes
The function f
takes a dummy argument and returns a string.
f c=[b=<<g]!!0++show g;b c=[[[show 9!!0,show 1!!0..]!!6..]!!c];g=[93,0,90,52,82,89,52,51,51,94,84,24,24,39,34,34,106,95,102,110,0,94,50,89,0,90,52,82,82,82,106,95,102,110,0,48,24,24,39,35,106,95,102,110,0,40,24,24,39,37,37,84,24,24,45,37,37,84,24,24,90,84,50,94,52]
Try it online!
Quine 3, 803 bytes
Everything after the LANGUAGE
pragma is an anymous function taking a dummy argument and returning a string.
{-#LANGUAGE CPP#-}(\q(_:_:_:_:_:_:_:_:z)y(#)_->(y(\k x->'&':q:k:q:x)#y(\k x->'%':q:'\\':k:q:x)$y(:)#y(:)$ \x->x)z)'\''__TIME__(\(?)v k x->v$k?x)$ \(&)(%)v->v&'{'&'-'&'#'&'L'&'A'&'N'&'G'&'U'&'A'&'G'&'E'&' '&'C'&'P'&'P'&'#'&'-'&'}'&'('%'\\'&'q'&'('&'_'&':'&'_'&':'&'_'&':'&'_'&':'&'_'&':'&'_'&':'&'_'&':'&'_'&':'&'z'&')'&'y'&'('&'#'&')'&'_'&'-'&'>'&'('&'y'&'('%'\\'&'k'&' '&'x'&'-'&'>'%'\''&'&'%'\''&':'&'q'&':'&'k'&':'&'q'&':'&'x'&')'&'#'&'y'&'('%'\\'&'k'&' '&'x'&'-'&'>'%'\''&'%'%'\''&':'&'q'&':'%'\''%'\\'%'\\'%'\''&':'&'k'&':'&'q'&':'&'x'&')'&'$'&'y'&'('&':'&')'&'#'&'y'&'('&':'&')'&'$'&' '%'\\'&'x'&'-'&'>'&'x'&')'&'z'&')'%'\''%'\\'%'\''%'\''&'_'&'_'&'T'&'I'&'M'&'E'&'_'&'_'&'('%'\\'&'('&'?'&')'&'v'&' '&'k'&' '&'x'&'-'&'>'&'v'&'$'&'k'&'?'&'x'&')'&'$'&' '%'\\'&'('&'&'&')'&'('&'%'&')'&'v'&'-'&'>'&'v'
Try it online!
Characters
Quine 1:
"S`adeimnprtu
Quine 2:
!+,.0123456789;<=[]bcfghosw
Quine 3:
#$%&'()-:>?ACEGILMNPTU\_kqvxyz{}
How it works
Quine 1
putStr`mappend`print`id`"putStr`mappend`print`id`"
Quine 1 is a modified version of my recent Golf you a quine answer (with improvements by H.PWiz):
- Since full programs are not needed,
main=
has been removed.
<>
and $
have been replaced by their near-synonyms mappend
and id
.
This frees up the vital characters =<>
and the helpful operator $
for the other quines.
Quine 2
f c=[b=<<g]!!0++show g;b c=[[[show 9!!0,show 1!!0..]!!6..]!!c];g=[93,0,......]
Quine 2 uses somewhat similar methods to program 2 of my recent Mutually Exclusive Quines answer, but adapted to quine itself directly and especially to avoid using character literals, which are needed for quine 3. Both of these are achieved with the help of the show
function, which by sheer luck hasn't had any of its characters used yet.
This quine uses tabs instead of spaces, but I've used spaces below for readability.
g
is the quine data, as a list of integers at the end of the code. Each number represents a character from the rest of the code.
- The numbers are shifted by
9
, so that tab is 0
. This makes the encoding a bit shorter by allowing the lowercase letters for the function and variable names to fit in 2 digits.
b c=[[[show 9!!0,show 1!!0..]!!6..]!!c]
is a function to convert a number to a character (actually a one-character string).
[[show 9!!0,show 1!!0..]!!6..]
is a character range starting with a tab character, which is indexed into with !!c
.
- The tab character itself is produced by indexing into another range
[show 9!!0,show 1!!0..]
, starting with the digit characters '9'
and '1'
and jumping down in steps of 8.
- The digit characters are produced by indexing into the
show
string of the corresponding digit.
f c=[b=<<g]!!0++show g
is the main function. c
is a dummy argument.
b=<<g
uses =<<
to convert each number in g
to its character. (The use of =<<
rather than e.g. map
is why b
needs to wrap its returned character in a list.)
show g
gives the string representation of g
's list, and ++
concatenates the strings.
- Because
=<<
has lower precedence than ++
, some bracketing is needed. To avoid using ()
(reserved for quine 3), [...]!!0
indexes into a list with one element.
Quine 3
By design of the other quines, quine 3 still has access to parentheses, lambda expressions, character literals, and the string/list constructor :
. This will be enough to construct a function that prepends the quine's code to a string.
Unfortunately, all lower case vowels (except sometimes y
) have been used, leaving no useful alphanumeric builtin functions. Also []""
are gone. This leaves no normal way to construct an empty string to start pretending the code to.
However, nearly all uppercase letters are still available, so a LANGUAGE
pragma to get a language extension is possible. Again by sheer luck, CPP
(enable C preprocessor) is the only language extension named with only uppercase letters. And CPP macros often have uppercase names.
So to get the essential empty string, the quine enables CPP
, uses the __TIME__
macro to get a string constant of the form "??:??:??"
(conveniently guaranteed to always have the same length), and pattern matches on it.
{-#LANGUAGE CPP#-}(\q(_:_:_:_:_:_:_:_:z)y(#)_->(y(\k x->'&':q:k:q:x)#y(\k x->'%':q:'\\':k:q:x)$y(:)#y(:)$ \x->x)z)'\''__TIME__(\(?)v k x->v$k?x)$ \(&)(%)v->v&'{'&'-'&......
After the language pragma, the quine consists of a lambda expression binding its parameters to these four arguments (leaving a final dummy parameter _
to be applied later):
q
bound to '\''
, giving a single quote character;
_:_:_:_:_:_:_:_:z
bound to __TIME__
, aka a string like "??:??:??"
, thus making z
an empty string;
y
bound to (\(?)v k x->v$k?x)
, a lambda combinator used to help convert the quine data from left associated ("foldl") to right associated ("foldr") form;
- The operator
(#)
bound to \(&)(%)v->v&'{'&'-'&...
, the quine data itself.
The quine data is given in a form of Church encoding, a lambda expression with parameters (&)(%)v
.
- By applying the expression to particular values to instantiate
(&)
, (%)
and v
, this encoding can be used either to build the core code of the quine or to rebuild the quine data representation itself.
- By Haskell's default fixity rule,
&
and %
become left associative operators inside the lambda. Thus the character parameters become combined with the initial v
starting from the left.
- For most characters
k
, there is a corresponding &'k'
.
- When
k
is '
or \
, which need to be escaped inside character literals, the encoding is instead %'\k'
.
Since the data encoding is left associative, but strings are built in a right associative manner, the combinator y = (\(?)v k x->v$k?x)
is introduced to bridge the mismatch.
y(...)
is intended to build suitable functions for using as the quine data's (&)
and (%)
operators.
v
is a function from strings to strings (the quine data's intended v
s being examples).
k
is a character, x
a string, and ?
an operator that combines them into a new string. (For the core code, (?)=(:)
. For actually reconstructing the quine data representation, it's more complicated.)
- Thus
y(?)v k = \x->v$k?x
is another function from strings to strings.
As an example of how this changes associativity, if (&)=y(:)
:
(v&k1&k2&k3) x
= (((v&k1)&k2)&k3) x
= y(:)(y(:)(y(:)v k1)k2)k3 x
= y(:)(y(:)v k1)k2 (k3:x)
= y(:)v k1 (k2:(k3:x))
= v (k1:(k2:(k3:x)))
= v (k1:k2:k3:x)
More generally, when (#)
is the quine data function and f1,f2
are functions combining characters with strings:
(y(f1)#y(f2)$v) x
= (...(y(f1)(y(f1)v '{') '-')...) x
= v(f1 '{' (f1 '-' (... x)))
applying the quine data function with (&)=y(f1)
and (%)=y(f2)
, and this uses the prescribed f1
and f2
to combine the quine data's characters with x
, and then passes the resulting string to v
.
The body of the main lambda expression puts this all together:
(y(\k x->'&':q:k:q:x)#y(\k x->'%':q:'\\':k:q:x)$y(:)#y(:)$ \x->x)z
'&':q:k:q:x
for a character k
prepends &'k'
to the string x
, while '%':q:'\\':k:q:x
prepends %'\k'
, which are their original quine data forms.
- Thus
y(\k x->'&':q:k:q:x)#y(\k x->'%':q:'\\':k:q:x
are the right parameters for rebuilding the quine data representation, prepended to the final z
(the empty string), and then passed on to the following function.
y(:)#y(:)
are the right parameters to prepend the quine's core code to a string, without other modification.
- Finally the
\x->x
gets to do nothing with the constructed quine, which is returned.
Since there are close votes I'll undelete the sandbox post for discussion: https://codegolf.meta.stackexchange.com/a/16053/9365
– Dom Hastings – 2018-04-27T19:58:56.953I notice that the sandbox comments mention that function submissions are allowed, but the challenge says nothing about it - I was assuming the opposite as the default for quines. – Ørjan Johansen – 2018-04-27T20:01:07.213
@ØrjanJohansen Perhaps I misunderstand the rules, but I thought function submissions were allowed by default for all questions. At least one function exists in the Golf You A Quine For Great Good question: https://codegolf.stackexchange.com/a/60148/9365
– Dom Hastings – 2018-04-27T20:25:12.4832Related (Kind of the converse challenge - your quines have to output each other instead of themselves) – Nathaniel – 2018-04-29T10:34:28.143
1What about trailing newlines? If one of my quines prints one, does the other have to avoid doing so? (I suspect that most answers don't do this.) – Nathaniel – 2018-04-30T11:23:29.400
@Nathaniel Assuming TIO shows trailing newlines properly (I know it does for Haskell and it seems to do so for Ruby, but I don't know how to test in the golflangs), all the submissions with TIO links handle trailing newlines properly (only Ruby has one). That leaves yours and Javascript, and the latter returns strings from functions so I suspect it works as well. – Ørjan Johansen – 2018-04-30T12:55:10.543
@ØrjanJohansen I see. I've added a version to my answer that avoids the trailing newline in one of the quines. If the OP clarifies the rules I will use that and update my score. – Nathaniel – 2018-04-30T13:09:00.410
@Nathaniel as long as the input hash matches the output, it's fine in my understanding. I'm not sure where the community stands on having a trailing newline printed when one doesn't exist in the source? Personally I'd be happy to see solutions with a newline output if it showcases a higher number of quines since I'm interested in seeing other approaches. I wonder if a meta question is necessary (orbhas already been answered?) – Dom Hastings – 2018-04-30T14:06:59.743
2
@DomHastings I couldn't find a meta question, so I asked one.
– Nathaniel – 2018-05-01T12:16:10.320