上に書いたものについて、同じ部分を変数 var に置き換えておきます。
var = "main = putStr$..(1)..";main=putStr$..(2)..
ここで、このプログラムを実行すると..(2)..が出力されるわけですが、
var= ”...” という形で始まる必要があるので、
var = "main = putStr$..(1)..";main=putStr$"var = " ++ show var ..(2')..
という形に書けるはずです。
ここで、 “show var” という部分は、 var の内容を文字列に変換するものです。
つまりこれを実行すると、
var = "main = putStr$..(1)....(2').."
となります。
元々、変数を使った理由は後半に、putStr がネストしていたからで、それを踏まえて..(2’)..が ;main=... と表すようにしておきます。つまり、..(2’).. を ++ ”;”++var に置き換えます。
var = "main = putStr$..(1)..";main=putStr$"var = " ++ show var ++ ";" ++ var
-- => var = "main = putStr$..(1)..;main=putStr$..(1).."
ここまで来ると、もう..(1)..の形も決まっています。
ただし、”“の中で”を使う必要があるので、”とエスケープします。
というわけで、 (1) を “var = ” ++ show var ++ ”;” ++ var” と置き換えます。
var = "main = putStr$\"var = \" ++ show var ++ \";\" ++ var";main = putStr$"var = " ++ show var ++ ";" ++ var
これで Quine になりました!!!!!
割と思いつくのに時間がかかったのですが、ちゃんとステップごとにやればどうにかなる気がします。
もう1つ例を出します。
発想を全く変えて、1つの引数を受け取ったらそれを複製する関数を書きます。
\(\lambda\) 計算を知っている人には自然なのかもしれません。
\((\lambda x.xx)(\lambda x.xx)\) という項の類似のつもりで書きました。(私は \(\lambda\) 計算に詳しくないのでよく知りません。もしかしたら型付き \(\lambda\) 計算と呼ばれるやつには、もっとそれっぽいのがあるのかも知れません。)
(\x -> putStr(x++" "++show x)) "(\\x -> putStr(x++\" \"++show x)"
このプログラムは、main がないので、正しくコンパイルして実行することはできませんが、
インタプリタ上で実行することはできます。(たとえば ghci)
コンパイルできる形で書こうと思ったのですが、イマイチ良い書き方が思いつきませんでした。