Церковные булевы

33

Церковные булевы

Церковь булева функция , которая возвращает xдля истинно и yдля ложных , где xэто первый аргумент функции и yявляется вторым аргументом функции. Дополнительные функции могут быть составлены из этих функций, которые представляют and not or xorи impliesлогические операции.

Вызов

Построить булеву Церковь и and not or xorи impliesцерковные ворота на языке по вашему выбору. and orи xorдолжен принимать две функции (представляющие логические значения Церкви) и возвращать функцию (представляющую другое логическое значение Церкви). Точно так же, notследует инвертировать функцию, которую он выполняет, и impliesлогический элемент должен выполнять логическую, подразумевающую логику, где первый аргумент impliesвторой.

счет

Общая длина всего кода, необходимого для создания церковного trueи falseна вашем языке and not or xorи impliesцерковных ворот, за исключением названия функции. (например, false=lambda x,y:yв Python будет 13 байт). Вы можете использовать эти имена позже в своем коде, считая их на 1 байт до общего количества байтов в этих воротах.

Примеры псевдокода:

Функции, которые вы создаете, должны иметь возможность вызываться позже в вашем коде следующим образом.

true(x, y) -> x
false(x, y) -> y
and(true, true)(x, y) -> x
and(true, false)(x, y) -> y
# ... etc
Райан Шефер
источник
2
Должны ли мы рассматривать входные данные функции (или ближайшие заменители) как функции черного ящика, или мы можем проверять код внутри? И должны ли возвращаемые значения логических операций быть теми же функциями, которые были определены ранее как логические значения Церковного, или они могут быть чем-то еще, что делает то же самое?
Несвязанная строка
1
@JonathanAllan Я отредактировал это так, чтобы это было правильно. Подсказка такая, какая должна быть сейчас.
Райан Шефер
2
Можем ли мы принять списки в качестве аргументов (например true([x, y]), and([true, true])([x, y]))?
ar4093
2
@RyanSchaefer Я думаю, вам следует пересмотреть вопрос о том, чтобы аргументы находились в упорядоченном списке, так как можно просто обернуть аргументы в начале решения. Я не думаю, что требование что-либо делает, чтобы улучшить эту проблему (фактически я думаю, что это ограничивает интересный потенциал игры в гольф). Конечно, это только мое мнение, и это хорошо, если вы не согласны.
FryAmTheEggman
1
Очки довольно запутанные. Разве не было бы лучше позволить людям отправлять анонимные функции, но если они используют их в других частях, они должны назначать их, как обычно
Джо Кинг

Ответы:

14

Двоичное лямбда-исчисление , 13,875, 12,875 байт (103 бита)

Язык двоичного лямбда-исчисления (BLC) Джона Тромпа - это в основном эффективный формат сериализации для лямбда-исчисления. Он отлично подходит для этой задачи, поскольку нотация Церкви - это даже «идиоматический» способ работы с логическими значениями в BLC.

Я использовал следующие лямбда-функции для комбинаторов, некоторые из которых я скопировал и сыграл в гольф из ответа Хаскелла: которые были найдены путем исчерпывающего поиска с доказательством ограничения в 20 β-сокращений для каждого случая. Есть большая вероятность, что они будут кратчайшими.

True:  (\a \b a)
False: (\a \b b)
Not:   (\a \b \c a c b)
And:   (\a \b b a b)
Or:    (\a a a)
Xor:   (\a \b b (a (\c \d d) b) a)
Impl:  (\a \b a b (\c \d c))

Они переводят в следующие (двоичные) кодовые последовательности BLC:

 bits |  name | BLC
------+-------+---------
    7 | True  | 0000 110
    6 | False | 0000 10
   19 | Not   | 0000 0001 0111 1010 110
   15 | And   | 0000 0101 1011 010
    8 | Or    | 0001 1010
   28 | Xor   | 0000 0101 1001 0111 0000 0101 0110
   20 | Impl  | 0000 0101 1101 0000 0110

Вышеуказанные функции имеют общую длину 111 бит (13,875 байт), длину 103 бит (12,875 байт). Их не нужно выравнивать по границам байтов для использования внутри программы, поэтому имеет смысл считать дробные байты.

Между комбинаторами нет повторного использования кода, поскольку в BLC нет переменных / ссылок / имен - все должно быть скопировано. Тем не менее, эффективность кодирования обеспечивает довольно сжатое представление.

Павел Поточек
источник
1
Я не знаю, но будет And: (\a \b a b a)работать?
TSH
Да, это работает. Я фактически использовал эту формулу для моих кодовых последовательностей. Я просто забыл обновить соответствующую функцию лямбда (теперь исправлено). Эквивалентная функция работает Или: \a \b a a b. Это длиннее, чем тот, который я использовал в BLC.
Павел Поточек
25

Haskell , 50 - 6 = 44 байта

-1 байт благодаря Khuldraeseth na'Barya, и -1 байт благодаря Кристиану Сиверсу.

t=const
f=n t
n=flip
a=n n f
o=($t)
x=(n>>=)
i=o.n

Попробуйте онлайн!

Nitrodon
источник
2
Примечание стороны: вы можете определить Showэкземпляры для constи const idи печатать церковные булевы непосредственно. Попробуйте онлайн! ,
Ними
aможно сократить
Халдрасет на'Барья
4
Почему никто не использует f=n t?
Кристиан Сиверс
3
Вы можете сохранить байт, используя t=pureвместо t=const.
Джозеф Сибл-Восстановить Монику
4
@JosephSible Я попробовал это изначально. К сожалению, t=pureприведет к ошибке при попытке применить a, o, xили iк нему. Объявление типа tисправления стоит больше байтов, чем просто использование t=const.
Нитродон
9

Python 2 , (-3?)  101  95 байт

Дэвид Бизли съест твое сердце!

-6 спасибо Часу Брауну (перенес повторение :в текст объединения>. <)

exec'=lambda x,y=0:'.join('F y;T x;N x(F,T);A x(y,F);O x(T,y);X x(N(y),y);I O(y,N(x))'.split())

Попробуйте онлайн!

Я думаю, что это может быть 95 - 3потому, что я не использую функции A, Xили I, но я использую один =для присваивания (перед lambda). Может быть, я не могу удалить любой; может я вообще получу удалить 3,5?

Джонатан Аллан
источник
@ Райан Шефер, я могу удалить три или я execимею в виду, что я не могу? Я вижу, что происходит в любом случае - я не использую A, X или I, но код не будет работать без них. (Может быть, я даже удаляю 3,5 ?!)
Джонатан Аллан
95 байтов (до -3)
Час Браун
Спасибо @Chas! Толстая кишка, которая проскользнула в сеть :) Хорошая работа по замене -1 BTW
Джонатан Аллан
7

JavaScript (Node.js) , 92 86 83 - 7 = 76 байт

t=p=>q=>p
f=t(q=>q)
n=p=>p(f)(t)
a=p=>n(p)(f)
o=p=>p(t)
x=p=>p(n)(f())
i=p=>n(p)(t)

Попробуйте онлайн! Ссылка включает в себя основные тестовые случаи. Изменить: Сохранено 6 9 байт благодаря @tsh.

Нил
источник
1
кажется , вы не можете утверждать это как -7 , так как t, f, nиспользуются.
TSH
1
@tsh Я не так понимаю систему начисления очков; это явно исключает имя в определении, хотя имя в использовании стоит 1 байт.
Нил
@Neil вы не можете претендовать на байтовую скидку для имен функций, которые вызываются с помощью кода ( t, fи nв вашем случае).
галантный
2
@asgallant нет. Это не байты для имени и 1 байт, когда он используется позже. 'T fnaox i' - это не байты, тогда 1 байт, когда используется позже. Я хотел улучшить удобочитаемость, но теперь я понимаю, что должен был просто оставить игру в гольфе, и уже слишком поздно ее менять
Райан Шефер,
@RyanSchaefer где это правило? Я никогда не видел, чтобы это делалось так.
asgallant
6

Python 2 , 133 - 6 = 127 94 байта

exec"t!u;f!v;n!u(f,t);a!u(v,f);o!u(t,v);x!u(n(v),v);i!o(v,n(u))".replace('!','=lambda u,v=0:')

Попробуйте онлайн!

Бесстыдно крадет подлую идею ответа Джонатана Аллана ; байты не вычитаются.

Час Браун
источник
Я собирался опубликовать ответ на свой вопрос, но я не был уверен, было ли это разрешено, и я думаю, что это противоречит его духу. Поэтому я думаю, что я просто буду сопровождать вас. Вместо того, чтобы использовать списки, есть ли в любом случае вы можете использовать функции, которые вводятся сами, и конкретный способ, которым они возвращают свои входные данные, чтобы сократить код?
Райан Шефер
Держу пари, что хотя ответ «да», в Python это будет значительно дольше.
Несвязанная строка
Я исправлен
несвязанная строка
@ Mr.Xcoder Вы правы, у меня было неправильное количество байтов для функции примера. Им будет разрешено удалить 6 байтов, хотя для имен функций.
Райан Шефер
@Мистер. Xcoder: модифицировано в соответствии с вашими наблюдениями.
Час Браун
4

J 67 байт - 7 = 60

t=.[
f=.]
n=.~
a=.2 :'u v]'
o=.2 :'[u v'
x=.2 :'u~v u'
i=.2 :'v u['

Попробуйте онлайн!

Стоит отметить:

Функции высшего порядка работают в J иначе, чем в функциональном языке. Чтобы создать новый глагол из 1 или 2 существующих глаголов, вам нужно использовать наречие (в случае 1) или соединение (в случае 2).

Синтаксически, наречия идут после глагола, и соединения происходят между ними. Таким образом, чтобы «не» глагол fвы делаете f n, а «и» глаголы fи gвы f a g.

Ион
источник
4

Wolfram Language (Mathematica) , 61-7 = 54 байта

t=#&
f=#2&
a=#2~#~f&
o=t~#~#2&
n=f~#~t&
x=n@#~#2~#&
i=#2~#~t&

Попробуйте онлайн!

не в гольф: вдохновленный Википедией ,

t[x_, y_] := x
f[x_, y_] := y
and[x_, y_] := x[y, f]
or[x_, y_] := x[t, y]
not[x_] := x[f, t]
xor[x_, y_] := y[not[x], x]
imply[x_, y_] := x[y, t]
Римский
источник
Уверен, что новые строки необходимы для разделения определений функций. Также вы ссылаетесь на tf и n в других определениях функций, поэтому вы не можете вычесть их, поэтому 61-4 = 57.
Джонатан Аллан
@JonathanAllan Я перечитал инструкции по подсчету очков и согласен с тем, что переводы должны учитываться, спасибо. Я не согласен с вашей второй частью: когда я повторно использую имена, я действительно считаю их как «1 байт к общему количеству байтов этих ворот», что подразумевается здесь, когда я использую 1-байтовые имена. Поскольку мое чтение инструкций идет, нет никакого упоминания о дальнейшем учете их как одного байта к общему количеству оригинального определения. Итак, я иду с N-7 байтов. Кроме того, другой комментарий ОП поясняет: «Это не байты для имени и 1 байт, когда оно будет использовано позже».
Роман
Я прочитал «1 байт позже», чтобы обозначить, что использование в другой функции стоит байт. Это соответствует тому, как другие забили тоже.
Джонатан Аллан
@JonathanAllan Я менее заинтересован в толковании и больше в коде в гольф 😀
Роман
4

Недогрузки , 56 52 байт

(~!)(!)((~)~*):((!)~^)*(:^)(~(!)~^(~)~*)(()~(~)~^~*)

Попробуйте онлайн! (включает тестовый набор и текстовые части программы)

Это удивительно хорошо для esolang очень низкого уровня. (По этой причине в Underload очень часто используются церковные цифры, церковные логические значения и т. Д .; в языке нет встроенных чисел и логических значений, и это один из самых простых способов их симуляции. закодируйте логические числа как церковные цифры 0 и 1.)

Для тех, кто в замешательстве: недогрузка позволяет вам определять многократно используемые функции, но не позволяет вам называть их обычным способом, они просто как бы плавают в стеке аргументов (так что если вы определяете пять функций, а затем хотите вызвать первую Вы определили, что вам нужно написать новую функцию, которая принимает пять аргументов и вызывает пятый из них, а затем вызывает ее с недостаточным количеством аргументов, чтобы она могла искать свободные аргументы). Вызов их уничтожает их по умолчанию, но вы можете изменить вызов, чтобы сделать его неразрушающим (в простых случаях вам просто нужно добавить двоеточие к вызову, хотя сложные случаи встречаются чаще, потому что вам нужно убедиться, что копии в стеке, не мешайте), так что поддержка функций Underload имеет все требования, которые нам нужны из этого вопроса.

объяснение

правда

(~!)
(  )  Define function:
 ~      Swap arguments
  !     Delete new first argument (original second argument)

Это довольно просто; мы избавляемся от аргумента, который нам не нужен, и аргумента, который нам нужен, просто остается там, служа в качестве возвращаемого значения.

ложный

(!)
( )   Define function:
 !      Delete first argument

Это еще проще.

не

((~)~*)
(     )  Define function:
    ~*     Modify first argument by pre-composing it with:
 (~)         Swap arguments

Это забавно: он notвообще не вызывает свой аргумент, он просто использует композицию функций. Это обычная уловка в Underload, в которой вы вообще не проверяете свои данные, вы просто меняете их функционирование, предварительно и после компоновки. В этом случае мы модифицируем функцию, чтобы поменять ее аргументы перед запуском, что явно отрицает церковную цифру.

а также

:((!)~^)*
 (     )   Define function:
     ~^      Execute its first argument with:
  (!)          false
               {and implicitly, our second argument}
        *  Edit the newly defined function by pre-composing it with:
:            {the most recently defined function}, without destroying it

Вопрос позволяет определять функции в терминах других функций. Мы определяем «и» далее, потому что чем позже было определено «нет», тем легче его использовать. (Это не вычитает из нашей оценки, потому что мы вообще не называем «не», но экономит байты при повторной записи определения. Это единственный раз, когда одна функция ссылается на другую, потому что ссылается на любую функцию но последнее определение будет стоить слишком много байтов.)

Определение здесь and x y = (not x) false y. Другими словами, если not x, тогда мы вернемся false; в противном случае мы вернемся y.

или

(:^)
(  )  Define function:
 :      Copy the first argument
  ^     Execute the copy, with arguments
          {implicitly, the original first argument}
          {and implicitly, our second argument}

@Nitrodon указал в комментариях, что or x y = x x yобычно короче or x y = x true y, и это оказывается правильным и в Underload. Наивная реализация этого была бы(:~^) , но мы можем отыграть дополнительный байт, отметив, что не имеет значения, запускаем ли мы первый аргумент или его копию, результат одинаков в любом случае.

Недостаточная нагрузка на самом деле не поддерживает карри в обычном смысле, но такие определения заставляют ее выглядеть так, как будто это происходит! (Хитрость заключается в том, что неиспользуемые аргументы просто остаются рядом, поэтому вызываемая вами функция будет интерпретировать их как свои собственные аргументы.)

подразумевает

(~(!)~^(~)~*)
(           )  Define function:
 ~               Swap arguments
     ~^          Execute the new first (original second) argument, with argument:
  (!)              false
                   {and implicitly, our second argument}
       (~)~*     Run "not" on the result

Определение , используемое здесь implies x y = not (y false x). Если у истинно, это упрощается not false, то есть true. Если у ложно, это упрощается not x, давая нам таблицу истинности, которую мы хотим.

В этом случае мы используем notснова, на этот раз переписывая его код, а не ссылаясь на него. Он просто написан напрямую, (~)~*без скобок, поэтому вызывается, а не определяется.

исключающее

(()~(~)~^~*)
(          )  Define function:
   ~   ~^       Execute the first argument, with arguments:
    (~)           "swap arguments"
 ()               identity function
         ~*     Precompose the second argument with {the result}

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

Когда первый аргумент верно, поэтому мы производим отредактированную версию второго аргумента , что свопы аргументов перед запуском, то есть Precompose с «аргументами свопа», то есть not. Таким образом, истинный первый аргумент означает, что мы возвращаем notвторой аргумент. С другой стороны, ложный первый аргумент означает, что мы сочиняем с функцией тождества, т.е. ничего не делаем. Результатом является реализация xor.

оборота ais523
источник
or x y = x x yсохраняет несколько байтов or x y = x true y.
Нитродон
Недостаточная загрузка часто бывает нелогичной, когда речь идет о замене литералов повторно используемыми переменными, но в этом случае получается, что это преобразование экономит больше байтов, чем ожидалось, а не меньше. Спасибо за улучшение!
ais523
3

Java 8, оценка: 360 358 319 271 233 (240-7) байт

interface J<O>{O f(O x,O y,J...j);}J t=(x,y,j)->x;J f=(x,y,j)->y;J n=(x,y,j)->j[0].f(y,x);J a=(x,y,j)->j[0].f(j[1].f(x,y),y);J o=(x,y,j)->j[0].f(x,j[1].f(x,y));J x=(x,y,j)->j[0].f(j[1].f(y,x),j[1].f(x,y));J i=(x,y,j)->j[0].f(j[1].f(x,y),x);

Это было сложнее, чем я думал, когда начинал. Особенно implies. Во всяком случае, это работает .. Возможно, можно немного поиграть в гольф здесь и там. РЕДАКТИРОВАТЬ: Хорошо, не повторное использование функций, а просто дублирование одного и того же подхода намного дешевле с точки зрения подсчета байтов для Java. И я получаю полный бонус -7 за то, что не использовал ни одну из функций.

Попробуйте онлайн.

Объяснение:

// Create an interface J to create lambdas with 2 Object and 0 or more amount of optional
// (varargs) J lambda-interfaces, which returns an Object:
interface J<O>{O f(O x,O y,J...j);}

// True: with parameters `x` and `y`, always return `x`
J t=(x,y,j)->x;
// False: with parameters `x` and `y`, always return `y`
J f=(x,y,j)->y;

// Not: with parameters `x`, `y`, and `j` (either `t` or `f`), return: j(y, x)
J n=(x,y,j)->j[0].f(y,x);

// And: with parameters `x`, `y`, and two times `j` (either `t` or `f`), return:
//      j1(j2(x,y), y);
J a=(x,y,j)->j[0].f(j[1].f(x,y),y);

// Or: with parameters `x`, `y`, and two times `j` (either `t` or `f`), return:
//     j1(x, j2(x,y))
J o=(x,y,j)->j[0].f(x,j[1].f(x,y));

// Xor: with parameters `x`, `y`, and two times `j` (either `t` or `f`), return:
//      j1(j2(y,x), j2(x,y))
J x=(x,y,j)->j[0].f(j[1].f(y,x),j[1].f(x,y));

// Implies: with parameters `x`, `y`, and two times `j` (either `t` or `f`), return:
//          j1(j2(x,y), x)
J i=(x,y,j)->j[0].f(j[1].f(x,y),x);
Кевин Круйссен
источник
2

C ++ 17, 207−49 = 158 195 - 58 = 137 байт

Разрывы строки не нужны (кроме первых двух).

#define A auto
#define D(v,p)A v=[](A x,A y){return p;};
D(true_,x)
D(false_,y)
A not_=[](A f){return f(false_,true_);};
D(and_,x(y,false_))
D(or_,x(true_,y))
D(xor_,x(not_(y),y))
D(implies,x(y,true_))

Попробуйте онлайн!

Юнит-тестирование с утверждениями, такими как:

static_assert('L' == true_('L', 'R'));
static_assert('R' == not_(true_)('L', 'R'));
static_assert('L' == and_(true_, true_)('L', 'R'));
static_assert('L' == or_(true_, true_)('L', 'R'));
static_assert('R' == xor_(true_, true_)('L', 'R'));
static_assert('L' == implies(true_, true_)('L', 'R'));

ОБНОВЛЕНО: раньше я имел

A not_=[](A f){return[f](A x,A y){return f(y,x);};};

но ответ Романа указал путь к более короткой версии. Обратите внимание, что сейчас not_(std::plus<>)плохо сформирован, где раньше это было эквивалентно std::plus<>; но так std::plus<>как «не представляет собой булеву церковь», я думаю, что любое поведение в порядке по правилам.

Quuxplusone
источник
Не следует ли заменить «кроме первого» на «кроме первых двух»?
LF
@LF: Абсолютно правильно. Обновлено. :)
Quuxplusone
2

Forth (gforth) , 133 байта - 7 = 126 122

: j execute ;
: t drop ;
: f nip ;
: n ['] f ['] t rot j ;
: a dup j ;
: o over j ;
: x 2dup a n -rot o a ;
: m over n -rot a o ;

Попробуйте онлайн!

-4 байта благодаря Quuxplusone

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

Объяснение кода

\ Helper function to save some bytes
: j        \ define a new word
  execute  \ execute the word at the provided address
;          \ end word definition

\ True
: t        \ define a new word
  drop     \ drop the second argument
;          \ end the word

\ False
: f        \ define a new word
  nip      \ drop the first argument
;          \ end the word

\ Not - The "hardest" one because we have to reference true and false directly
: n        \ define a new word
  ['] f    \ get address of false
  ['] t    \ get the address of true
  rot      \ stick the input boolean back on the top of the stack
  j        \ call the input boolean, which will select the boolean to return
;          \ end the word

\ And 
: a        \ define a new word
  dup      \ duplicate the 2nd input value
  j        \ call the 2nd input on the first and second input
;          \ end the word

\ Or
: o        \ define a new word
  over     \ duplicate the 1st input value
  j        \ call the 1st input on the first and second input
;          \ end the word

\ Xor
: x        \ define a new word
  2dup     \ duplicate both of the inputs
  a n      \ call and, then not the result (nand)
  -rot     \ move the result behind the copied inputs
  o a      \ call or on the original inputs, then call and on the two results
;          \ end the word

\ Implies
: m        \ define a new word
  over     \ duplicate the 1st input value
  n        \ call not on the 1st input value
  -rot     \ move results below inputs
  a o      \ call and on the two inputs, then call or on the two results
;          \ end the word
reffu
источник
1
Вы повторяете длинное слово executeтри раза. Определение сокращений : j execute ;сэкономит вам 4 байта.
Quuxplusone
1

SKI-исчисление + C комбинатор, 36 байт

true=K
false=SK
not=C
and=CC(SK)
or=CIK
xor=C(CIC)I
implies=CCK

На самом деле я не знаю ни одного интерпретатора, который позволял бы вам определять дополнительные комбинаторы в терминах предыдущих, поэтому мне пришлось проверить это с помощью http://ski.aditsu.net/ , вставив нужные комбинаторы, например, CCKK(SK)pqвыходные данные q, показывая, что Kне подразумевает SK.

Нил
источник
1

Юлия 1,0 , 36 байт

(b::Bool)(x,y)=b ? x : y;i(x,y)=!x|y

Я не знаю, имеет ли это значение, я просто перегружаю нативный Boolтип, чтобы его можно было вызывать, поэтому я получаю большинство логических элементов бесплатно. К сожалению, у Джулии нет impliesворот, поэтому мне пришлось написать свою собственную функцию.

Попробуйте онлайн!

user3263164
источник
Я думаю, что вам все еще нужно включить перегруженные операторы в ваше представление ... но оценка не учитывает их, так как они просто имена? Таким образом, это будет +6 байтов от новой строки? Я не слишком уверен, как выигрыш работает с этим испытанием
Джо Кинг
Я не уверен на 100%, как это работает, но включение кода, который буквально ничего не делает, не имеет для меня никакого смысла.
user3263164
Даже если код уже объявлен, вы все равно должны его включить, иначе любая другая отправка языка игры в гольф будет иметь нулевые байты. Вы просто не должны назначать это чему-либо
Джо Кинг
1

C ++ 17, 202−49 = 153 193 - 58 = 135 байтов

Вдохновленный комментарием-обсуждением того, что в любом случае считается 2-арной функцией, вот карри версия моего предыдущего решения C ++ 17. Это на самом деле короче, потому что мы можем использовать тот же макрос для определения, not_что и для определения всех других функций!

#define D(v,p)auto v=[](auto x){return[=](auto y){return p;};};
D(true_,x)
D(false_,y)
D(not_,x(false_)(true_)(y))
D(and_,x(y)(false_))
D(or_,x(true_)(y))
D(xor_,x(not_(y))(y))
D(implies,x(y)(true_))

Попробуйте онлайн!

Этот проверен с утверждениями как

static_assert('R' == and_(true_)(false_)('L')('R'));
static_assert('L' == or_(true_)(false_)('L')('R'));

Обратите внимание, что or_определяется как эффективно

auto or_=[](auto x){return[=](auto y){return x(true_)(y);};};

Мы могли бы определить or_более "кратко" как

auto or_=[](auto x){return x(true_);};

но это будет стоить нам, потому что мы больше не будем использовать Dмакрос.

Quuxplusone
источник
Поскольку C ++ чувствителен к регистру, как насчет использования Trueи Falseвместо true_и false_? И похоже на других операторов. Это сэкономит 12 байтов.
Г. Слипен
@ G.Sliepen: алгоритм подсчета OP уже учитывает, что идентификаторы фактически имеют длину в один символ. Цитата: «Общая длина всего кода, необходимого для того, чтобы сделать Церковь истинной и ложной на вашем языке, а также и не или xor, и подразумевает ворота Церкви, исключая имя функции. (Например, false = lambda x, y: y в Python будет 13 байтов). Вы можете использовать эти имена позже в своем коде, когда они будут считать 1 байт до общего количества байтов в этих воротах. "
Quuxplusone
Ах, я пропустил это.
Г. Слипен
0

APL (dzaima / APL) , 47 байтов SBCS

Основано на J-решении Джоны .

trueи falseявляются инфиксными функциями, notявляются суффиксными операторами, а остальные являются инфиксными операторами.

true←⊣
false←⊢
and←{⍺(⍶⍹false)⍵}
not←⍨
or←{⍺(true⍶⍹)⍵}
xor←{⍺(⍶not⍹⍶)⍵}
implies←{⍺(⍹⍶true)⍵}

В соответствии с OP, это подсчитывает все от и до конца каждой строки, и считает каждый вызов предыдущим определением как один байт.

Попробуйте онлайн!

true и false - это левая и правая функции идентичности.

not просто меняет аргументы своей функции операнда.

Остальные реализуют дерево решений:

andиспользует правую функцию, чтобы выбрать результат левой функции, если истина, иначе результат falseфункции.

orиспользует левую функцию, чтобы выбрать trueif true, иначе результат правой функции .

xorиспользует правую функцию, чтобы выбрать отрицательный результат левой функции, ⍶notесли истина, иначе результат левой функции.

impliesиспользует левую функцию, чтобы выбрать результат правой функции, если истина, иначе результат trueфункции.

Адам
источник
0

Stax , 34 байта

¿S£↓♣└²≡é♫Jíg░EèΩRΦ♂°┤rà╝¶πï╡^O|Θà

Запустите и отладьте его на staxlang.xyz!

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

Распаковано (41 байт):

{sd}Y{d}{y{d}a!}X{ya!}{b!}{cx!sa!}{sx!b!}

Каждая пара { }представляет собой блок. Я использовал два регистра X и Y для хранения, trueи notя мог легко получить к ним доступ позже. К сожалению, это falseне может быть просто невозможностью, так как это оставит стек загроможденным и испортит один случай XOR.

Тестовый набор, прокомментирован

false
{sd}    stack:   x y
 s      swap:    y x
  d     discard: y

true
{d}    stack:   x y
 d     discard: x

not
{y{d}a!}    stack:  p
 y{d}       push:   p f t
     a      rotate: f t p
      !     apply:  p(f,t)

and
{ya!}    stack:  p q
 y       push:   p q f
  a      rotate: q f p
   !     apply:  p(q,f)

or
{b!}    stack:  p q
 b      copies: p q p q
  !     apply:  p q(q,p)

xor
{cx!sa!}    stack:  p q
 c          copy:   p q q
  x!        not:    p q nq
    s       swap:   p nq q
     a      rotate: nq q p
      !     apply:  p(nq,q)

implies
{sx!b!}    stack:  p q
 s         swap:   q p
  x!       not:    q np
    b      copies: q np q np
     !     apply:  q np(np,q)
Хулдрасет на'Барья
источник
0

Befunge-98 , 105 77 65 байт

Продолжаем играть с понятием «функция» в языках без функций… вот версия церковных логических выражений Befunge-98!

В этом ограниченном диалекте Befunge-98 программа состоит из серии «линий» или «функций», каждая из которых начинается с >инструкции («Вправо») в столбце x = 0. Каждую «функцию» можно идентифицировать по номеру строки (координата y). Функции могут принимать данные через стек Befunge , как обычно.

Строка 0 является особенной, потому что (0,0) является начальным IP. Чтобы создать программу, которая выполняет строку L, просто поместите инструкции в строку 0, которые, при выполнении, передают указатель инструкции на (x = L, y = 0).

Волшебство происходит в строке 1. Строка 1, когда выполняется, извлекает число Lиз стека и переходит на номер строки L. (Эта строка ранее была такой > >>0{{2u2}2}$-073*-\x, что может «абсолютный переход» к любой строке; но я только что понял, что, поскольку я знаю, что эта строка привязана к строке 1, мы можем «относительный переход»L-1 строк в чертовом количестве кода намного меньше.)

Линия 2 представляет церковь FALSE. При запуске она появляется два числа tи fиз стека , а затем летит к номеру строкиf .

Строка 3 представляет церковь TRUE. При запуске она появляется два числа tи fиз стека , а затем летит к номеру строкиt .

Строка 6, представляющая Церковь XOR, является инновационной. При выполнении она появляется два числа , aи bиз стека, а затем летит в линии aс вводом стека NOT EXEC b. Итак, если aпредставляет Церковь TRUE, результат a NOT EXEC bбудет NOT b; и если aпредставляет церковь FALSE, результат a NOT EXEC bбудет EXEC b.


Вот версия без присмотра с тестовой оснасткой. В строке 0 установите стек со своими данными. Например, 338значит IMPLIES TRUE TRUE. Убедитесь, что закрытие xпоявляется точно (x, y) = (0,15), иначе ничего не будет работать! Также убедитесь, что установка стека начинается с того ba, что программа фактически завершится с некоторым выводом.

Попробуйте онлайн!

>  ba 334  0f-1x
> >>1-0a-\x             Line 1: EXEC(x)(...) = goto x
> $^< <            <    Line 2: FALSE(t)(f)(...) = EXEC(f)(...)
> \$^                   Line 3: TRUE(t)(f)(...) = EXEC(t)(...)
> 3\^                   Line 4: OR(x)(y)(...) = EXEC(x)(TRUE)(y)(...)
> 3\2\^                 Line 5: NOT(x)(...) = EXEC(x)(FALSE)(TRUE)(...)
> 1\5\^                 Line 6: XOR(x)(y)(...) = EXEC(x)(NOT)(EXEC)(...)
> 2>24{\1u\1u\03-u}^    Line 7: AND(x)(y)(...) = EXEC(x)(y)(FALSE)(...)
> 3^                    Line 8: IMPLIES(x)(y)(...) = EXEC(x)(y)(TRUE)(...)

> "EURT",,,,@
> "ESLAF",,,,,@

Вот версия, байты которой я посчитал.

>>>1-0a-\x
>$^<< }u-30\<
>\$^
>3\^\
>3\2^
>1\5^
>2>24{\1u\1u^
>3^

Обратите внимание, что для определения функции на этом диалекте вы вообще не упоминаете ее имя; его «имя» определяется его исходным местоположением. Чтобы вызвать функцию, вы должны упомянуть ее «имя»; например, XOR( 6) определяется в терминах NOTи EXEC( 5и 1). Но все мои «имена функций» уже занимают только один байт. Таким образом, это решение не получает корректировок оценки.

Quuxplusone
источник