Вы можете Meta Quine?


25

Подобно другим головоломкам Куайна (точнее, этой ), напишите программу, которая сама создает исходный код.

Вот новый поворот: полученный код НЕ должен быть идентичен исходному. Скорее, он должен вывести другую программу, которая создаст первую.

Задача, связанная с вышеупомянутым, достигла этого путем перехода между двумя языками. Я думаю, что это будет сделано только на одном языке , но две (или более) версии источника должны значительно отличаться (см. Правила ниже). При таком ограничении односимвольные ответы будут запрещены, что потребует немного больше обдумывания для окончательного представления.


ПРАВИЛА

  1. Ваш код должен быть написан только на одном языке. (Несколько заявок, по одной для каждого языка вполне приемлемо.)
  2. Ваши разные версии кода должны быть синтаксически различны. Другими словами, если вы хотите нарисовать абстрактное синтаксическое дерево для вашего кода, должен быть хотя бы один другой узел.
    • Поставляя в AST не будет необходимости, но если вы чувствуете , склонны предоставлять по одному для каждой из ваших программ, он бы помочь в оценке.
  3. Вы можете создавать столько итераций, сколько пожелаете, если они все остаются синтаксически различными. (Подробнее поможет ваш счет, см. Ниже.)

SCORING

Ваша итоговая оценка будет означать среднюю продолжительность всех ваших программ, поделенную на количество программ.

Пример 1:

A (источник для B) = 50 символов
B (источник для A) = 75 символов
Окончательная оценка = 31,25

Пример 2:

A (источник для B) = 50 символов
B (источник для C) = 75 символов
C (источник для A) = 100 символов
Окончательная оценка = 25


18
Я один раз
mellamokb

1
@mellamokb har har ;-)
Гаффи

На самом деле это всего лишь более общая версия этой задачи, и ответы, которые там даны, также выиграют здесь.
перестал поворачивать против часовой стрелки

@leftaroundabout, требование синтаксических различий лишает законной силы «вращающуюся квину», так что это не является более общим.
Boothby

2
Никогда мета-квин мне не нравился.
Stack Tracer

Ответы:


35

Python, 0 (ограничение (68 + 3 n ) / (16 n ))

Если два абстрактных синтаксических дерева различны, если они имеют разные константы,

r='r=%r;n=(0x%XL+1)%%0x10...0L;print r%%(r,n)';n=(0xF...FL+1)%0x10...0L;print r%(r,n)

Есть 16 п программ длиной не более 68 + 3n, дающие асимптотическую оценку 0.

Если вам нужны программы с переменной структурой, мы можем реализовать двоичный сумматор на n битах. Здесь есть 2 n программ длины O ( n 2 ). Идет в цикле из-за сброшенного переносного бита.

s="""
print 's='+'"'+'"'+'"'+s+'"'+'"'+'"'
n=lambda m:reduce(lambda (s,c),y:(s+(c^y,),c&y),m,((),1))[0]
print s[:112]
t=n(t)
print "t=(%s,)+(0,)*%s"%(t[0],len(t)-1)
for i in range(len(t)-1):
    print i*' '+'for i in range(2):'
    print ' '+i*' '+['pass','t=n(t)'][t[i+1]]
print s[113:-1]
"""

print 's='+'"'+'"'+'"'+s+'"'+'"'+'"'
n=lambda m:reduce(lambda (s,c),y:(s+(c^y,),c&y),m,((),1))[0]
print s[:112]
t=(0,)+(0,)*10
for i in range(2):
 t=n(t)
 for i in range(2):
  t=n(t)
  for i in range(2):
   t=n(t)
   for i in range(2):
    t=n(t)
    for i in range(2):
     pass
     for i in range(2):
      t=n(t)
      for i in range(2):
       pass
       for i in range(2):
        pass
        for i in range(2):
         pass
         for i in range(2):
          t=n(t)
t=n(t)
print "t=(%s,)+(0,)*%s"%(t[0],len(t)-1)
for i in range(len(t)-1):
    print i*' '+'for i in range(2):'
    print ' '+i*' '+['pass','t=n(t)'][t[i+1]]
print s[113:-1]

Могу ли я быть смущен? Похоже, что результат идентичен источнику (не цель этой задачи)?
Гаффи

Посмотри во вложенном блоке. passбудет меняться на t=n(t)и обратно, во всех 2 ^ n комбинациях.
Boothby

Теперь я это вижу. Вы перепутали меня со всем повторением!
Гаффи

22
по какой-то причине мне нравятся очень длинные гольф-решения с крошечными оценками.
Boothby

Вау, ты полностью владел этим! Очень хорошо.
Клаудиу

4

Perl, оценка 110,25

Я должен признать, что я не очень хорош с муками. Я на 100% уверен, что есть возможности для улучшения. Решение основано на том же принципе решения Element ниже.

Первая программа - 264 символа.

$s='$a=chr(39);print"\$s=$a$s$a;";$s=reverse$s;for(1..87){chop$s}$s=reverse$s;print$s;$f++;if($f==0){$a=chr(39);print"\$s=$a$s$a;$s"}';$a=chr(39);print"\$s=$a$s$a;";$s=reverse$s;for(1..87){chop$s}$s=reverse$s;print$s;$f++;if($f==0){$a=chr(39);print"\$s=$a$s$a;$s"}

Вторая программа - 177 символов.

$s='$a=chr(39);print"\$s=$a$s$a;";$s=reverse$s;for(1..87){chop$s}$s=reverse$s;print$s;$f++;if($f==0){$a=chr(39);print"\$s=$a$s$a;$s"}';if($f==0){$a=chr(39);print"\$s=$a$s$a;$s"}

Я работаю над AST для этой записи (и записи Element).


Элемент , оценка 47,25

Первая программа 105 символов.

\ \3\:\$\'\[\\\\\`\(\`\]\#\2\1\'\[\(\#\]\`\ \3\:\$\'\[\\\\\`\(\`\]\#\` 3:$'[\\`(`]#21'[(#]` 3:$'[\\`(`]#`

Вторая программа - 84 символа.

\ \3\:\$\'\[\\\\\`\(\`\]\#\2\1\'\[\(\#\]\`\ \3\:\$\'\[\\\\\`\(\`\]\#\` 3:$'[\\`(`]#`

Я уверен, что есть много возможностей для улучшения.

В первой программе есть одна строка (в которой каждый символ экранирован, несмотря на большую избыточность), за которой следуют исполняемые части A и B. Часть A делает несколько вещей: печатает строку и экранирует каждый символ, печатает последнюю половину строки (которая является источником для части B), а затем не позволяет части B, которая следует за ней, что-либо делать.

Вторая программа - та же строка, за которой следует часть B. Часть B основана на простой квине; он печатает строку, которой предшествует экранированная версия. Это означает, что он печатает строку, и обе части A и B.


Я думаю, что это, вне всякого сомнения, доказывает валидность Element как языка программирования. Его так легко использовать, что я, настолько неопытный, что мне удалось написать только одного полного переводчика для Элемента, смог ответить на этот вопрос раньше, чем любой другой человек на всей этой планете из 7 000 000 000 человек. Парадигма элемента «один символ, одна функция, все время» означает, что весь код полностью однозначен. Язык универсален: за исключением того []{}, что любая команда может быть размещена в любом месте всей программы, не вызывая синтаксической ошибки. Это идеально.
PhiNotPi

4
Немного предвзято, не так ли? ;-)
Гаффи

3

VBA: (251 + 216) / 2/2 = 116,75

251

Sub a()
r=vbCrLf:c="If b.Lines(4, 4) = c Then"&r &"b.InsertLines 8, d"&r &"b.DeleteLines 4, 4"&r &"End If":d="b.InsertLines 6, c"&r &"b.DeleteLines 4, 2"
Set b=Modules("Q")
If b.Lines(4, 4) = c Then
b.InsertLines 8, d
b.DeleteLines 4, 4
End If
End Sub

216

Sub a()
r=vbCrLf:c="If b.Lines(4, 4) = c Then"&r &"b.InsertLines 8, d"&r &"b.DeleteLines 4, 4"&r &"End If":d="b.InsertLines 6, c"&r &"b.DeleteLines 4, 2"
Set b=Modules("Q")
b.InsertLines 6,c
b.DeleteLines 4,2
End Sub

Это запускается в MSAccess для использования Moduleобъекта. Модуль назван "Q"для игры в гольф. Разница в синтаксисе происходит от If ... Thenотсутствия в более короткой версии.


вы можете , скорее всего , уйти с изменением vbCrLFвvbCr
Тейлор Скотт

3

С ++, оценка 0,734194

Следующий исходный код выводит мета-квин порядка 999 на консоль (пояснение ниже):

#define X 1*(1+1)
#include<iostream>
#include<vector>
#define Q(S)auto q=#S;S
Q( \
  main() \
  { \
      using namespace std; \
      cout<<"#define X 1"; \
      int x=X==2?1000:X-1; \
      vector<int> factors; \
      for ( int p = 2; p <= x; ++p) \
      { \
        while ( x % p == 0 ) \
        { \
          factors.push_back( p ); \
          x /= p; \
        } \
      } \
      for ( int factor : factors ) \
      { \
        cout<<"*(1"; \
        for ( int i=1;i<factor;++i) \
          cout<<"+1"; \
        cout<<")"; \
      } \
      cout<<"\n#include<iostream>\n#include<vector>\n#define Q(S)auto q=#S;S\nQ("<<q<<")"; \
  })

Единственная строка, которая изменяется, это первая строка. Значение Xбудет 1000, 999, 998, ..., 3, 2, и затем оно начнется снова. Однако для того, чтобы каждый раз получать разные синтаксические деревья, Xпредставляется с точки зрения его факторизации простых чисел, где каждое простое число записывается в виде суммы 1s. AST различны, потому что основная факторизация целых чисел различна для каждого значения.

Программа напечатает сама себя, за исключением того, что первая строка будет изменена, а обратные слеши, разрывы строк и отступы Q(...)будут удалены.

Следующая программа вычисляет оценку моего ответа:

#include <iostream>

const int n = 1000;

int getProgramLength( int n )
{
  int sum = 442;
  for ( int p = 2; p*p <= n; ++p )
  {
    while ( n % p == 0 )
    {
      sum += 2 * ( 1 + p );
      n /= p;
    }
  }
  if ( n > 1 )
    sum += 2 * ( 1 + n );
  return sum;
}

int main()
{
  int sum = 0;
  for ( int i = 2; i <= n; ++i )
    sum += getProgramLength( i );
  std::cout << (double)sum/(n-1)/(n-1) << '\n';
}

Это напечатало 0.734194 к консоли. Очевидно, что 1000 можно заменить большими целыми числами, и в качестве предела счет приблизится к 0. Математическое доказательство с использованием дзета-функции Римана несколько запутано. Я оставляю это в качестве упражнения для читателя. ;)


2

JavaScript, 84,5 64 61

Две программы, обе длины 169 128 122.

(function c(){alert(/*
2/*/1/**/);return ('('+c+')()').replace(/\/([/\*])/,function(m,a){return a=='*'?'/\/':'/\*'});
})()

Прежде чем я играл в гольф, для вашего удовольствия от просмотра:

(function c() {
    var r = /\/([/\*])/;
    var f = function(m, a) { return a === '*' ? '/\/' : '/\*' };
    var p = '(' + c + ')();';
    p = p.replace(r, f);
    /* This is just a comment!
    console.log('Quine, part two!'); /*/
    console.log('Quine, part one!'); /**/
    return p;
})();

Возвращает новую программу и выводит текущую часть! Я мог бы сделать его короче без регулярного выражения, но ... я не хочу.


Нет, они синтетически разные. Как только вы добавите новые строки, то есть.
Ry-

2

J - (24 + 30) / 2/2 = 13,5 балла

Обратите внимание , что строки в J не обратные косая черта маскирования, но цитата маскирования а - ля Паскаля: 'I can''t breathe!'.

30$(,5#{.)'''30$(,5#{.)'         NB. program 1, 24 char
'30$(,5#{.)''''''30$(,5#{.)'''   NB. program 2, 30 char

Программа 1 имеет AST, noun verb hook nounа программа 2 имеет AST noun. Программа 2 является цитированной версией программы 1, которая при запуске просто возвращает программу 1, поэтому этот метод нельзя легко расширить до трех копий: P

Программа 1 работает, взяв копию кодовой части исходного кода, с кавычкой, добавленной впереди, и добавив пять из этих кавычек в конец ( (,5#{.)). Затем он циклически берет 30 символов из этой 16-символьной строки, что дает в результате именно Программу 2.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.