Суммируя? Это моя сильная сторона!

18

Вступление

Форте - это очень своеобразный эзотерический язык, основанный на концепции изменения значений чисел. В числах Forte не константы, а переменные, вы можете использовать LETинструкцию, чтобы назначить им новые значения.

Например, после выполнения LET 2=4-1отныне 2принимает значение 3, что означает, что всякий раз, когда значение 2появляется в выражении, оно вместо этого «заменяется» на 3. Выражение (1+1)*2теперь будет оцениваться как 9.

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

Соревнование

Вы должны написать интерпретатор для упрощенного подмножества LETвыражений Forte .

В качестве входных данных вы получите последовательность строк, следующую этой грамматике:

<line>::= <number>=<expression>

<expression>::= <number>|<expression>+<number>

Примечание: эта грамматика недопустима в Forte, потому что в ней отсутствуют номера строк, LET и круглые скобки (которые всегда обязательны)

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

Числа всегда будут неотрицательными целыми числами, вплоть до предела целочисленного типа вашего языка (или 2 ^ 32, в зависимости от того, что больше).

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

Это , выигрывает самый короткий код (в байтах)!

Другие правила

  • Формат ввода гибкий, например, вы можете взять одну строку с символами новой строки, списком строк, списком чисел ... То же самое относится и к выводу, если ясно, каков результат каждого выражения в вход.
  • Вы можете предоставить функцию, полную программу или решение для запуска в среде REPL, вызывая ее один раз для каждой строки.
  • Стандартные лазейки запрещены, в частности, вы не можете вызвать внешний интерпретатор Forte в своем коде.

Примеры

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

5=4
4
6=5
4        # 5 -> 4
7=1+2+5
7
7=5+2+1
4        # Order of operations matters! 5+2 -> 4+2 -> 6 -> 4
18=5+6+7
12
5=3
3        # Remember: 5 -> 4
10=6+4
3        # 6 -> 4 -> 3, 3+3 = 6 -> 3
Лео
источник
Является ли 0допустимый номер?
17
@orlp 0действителен («Числа всегда будут неотрицательными целыми числами»)
Лев
Должны ли мы принимать какие-либо арифметические операторы?
bacchusbeale
@ bacchusbeale Нет, просто суммирование.
Лев
Есть ли какое-то конкретное максимальное число, или оно такое же большое, как у целочисленного типа языка? Кроме того, было бы неверно выводить список чисел, одно из которых является результатом, верно? (например, распечатка словаря / карты, для которых число переходит на какое число)
zgrep

Ответы:

4

Желе , 28 байт

®y$ÐL
ṪÇ+Ç¥/Ṅ;®⁸Ǥ;©
⁸©ḷƓÇ€¤

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

Это одна из немногих программ Jelly, в которой кажется более уместным использование стандартного ввода. Это полная программа (написание функции было бы короче, но было бы запрещено правилами PPCG, потому что она не будет работать правильно во второй раз). Формат ввода выглядит следующим образом:

[[5,[4]],[6,[5]],[7,[1,2,5]],[7,[5,2,1]],[18,[5,6,7]],[5,[3]],[10,[6,4]]]

объяснение

Вспомогательная функция 1Ŀ (перевод целого числа в его значение)

®y$ÐL
   ÐL   Repeatedly, until there are no further changes,
  $       apply the following unary function to {the input}:
 y          replace values using the mapping table
®             stored in the register.
        {Then return the eventual result.}

Скорее всего, эта вспомогательная функция будет корректно работать либо с одним значением, либо со списком значений, в зависимости от способа yопределения. Если для одного значения задано более одного сопоставления, мы берем первое сопоставление из таблицы. Таблица отображения хранится в регистре (который в основном является просто переменной; у Jelly есть только одна переменная).

Вспомогательная функция 2Ŀ (оцените одну инструкцию LET)

ṪÇ+Ç¥/Ṅ;®⁸Ǥ;©
Ṫ               On the last element of {the input},
 Ç              Run 1Ŀ,
     /          left fold it via
    ¥             the following binary function:
  +                 add {the two arguments}
   Ç                and run 1Ŀ on {the result},
      Ṅ         write {the result} (and a newline) to standard output,
       ;®       append the value of the register,
            ;   prepend
           ¤      the following value:
         ⁸          {the input, without its last element}
          Ç         with 1Ŀ run on it
             ©  and store that value in the register {and return it}.

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

Основная программа

⁸©ḷƓÇ€¤
 ©       Initialize the mapping table
⁸        with the empty string (which is also the empty list)
  ḷ      then evaluate and discard
      ¤  the following value:
   Ɠ       a line from standard input, parsed into a data structure
    Ç€     with each element transformed via 2Ŀ
         {and leave the empty string to be printed implicitly}

Обычно, это даст нам первый аргумент командной строки при запуске в этом контексте, но его нет (мы берем данные из стандартного ввода), поэтому он работает в альтернативном режиме, который дает нам нулевую строку. Необходимость инициализировать регистр (из значения по умолчанию 0, которое вылетает y) означает, что мы не можем неявно упомянуть ввод пользователя, то есть взять его из стандартного input ( Ɠ) так же дешево, как и взять его из Аргумент командной строки ( ³или ) и возможность доступа к альтернативному использованию означает, что необычная (для Jelly) форма ввода на самом деле на байт короче.

Возможно, это невозможно. Я до сих пор не понял, почему вторая строка должна говорить, ⁸Ǥ;а не просто ;@Ç- эти две должны быть эквивалентны, насколько я понимаю, Jelly, учитывая отсутствие использования µ/ ð/ ø- но последняя по какой-то причине вылетает. Аналогичным образом, существуют различные другие способы перестановки программы без потери байтов, поэтому возможно, что я упустил способ сделать вещи немного короче.

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


источник
5

Perl 5 , 92 байта

90 байтов кода + -plфлаги.

sub f{($b=$h{$a=pop}//$a)!=$a?f($b):$a}s%(\d+)\+(\d+)%f($1)+f$2%e&&redo;/=/;$_=$h{f$`}=f$'

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

Я использую хеш-таблицу %hдля хранения сопоставления между числами.
Функция ( sub) fвозвращает номер, на который указывает ее входная карта (или ее входные данные, если она не указана): $h{$a=pop}извлекает номер, на который отображается входная карта. Если это не так, спасибо //$a, значение ($b=$h{$a=pop}//$a)является input ( $a). Мы удостоверяемся, что эти значения не являются самими входными данными, чтобы не зацикливаться бесконечно ( !=$a). Затем мы либо рекурсивно вызываем, fлибо возвращаем ввод.
Основная программа состоит из двух этапов:
- s%(\d+)\+(\d+)%f($1)+f$2%e&&redoоценивает первое добавление с правой стороны, при этом еще есть добавление: оно заменяется x+yрезультатом оценки f(x)+f(y).
- /=/;$_=$h{f$`}=f$'выполняет задание:/=/позволяет получить доступ к левой стороне с $`и правой стороне с $', затем $h{f$`}=f$'делает назначение. И мы также присваиваем его тому, $_что неявно печатается после каждой строки.

папа
источник
5

JavaScript (Node.js) , 81 байт

v=x=>(v[x]=v[x]||x,v[x]-x?v(v[x]):x)
f=x=>l=>v[v(x)]=l.reduce((p,x)=>v(v(x)+p),0)

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

Получает ввод, вызывая f со значением, которое нужно присвоить, затем вызывая результат этого с массивом значений, которые нужно сложить вместе. (т.е. f(5)([4])) Повторите для нескольких строк.

vиспользуется как функция для вычисления фактического текущего значения числа, а также как объект для хранения фактических значений. Сначала v[x]=v[x]||xубедитесь, что v[x]это определено. v[x]-xвыполняет сравнение, чтобы определить, является ли это фактическим числом или нет. Если число не отображается на себя, v(v[x])рекурсивно пытается снова, в противном случае верните x.

f выполняет вычисление и присваивание, карри для сохранения одного байта, где второй вызов возвращает вычисленное значение.

OinkIguana
источник
3

Haskell , 116 113 108 106 байт

(#)=until=<<((==)=<<)
e?((n,s):r)|m<-foldl1(\a b->e#(e#a+e#b))s=m:(\x->last$m:[e#x|x/=e#n])?r
e?r=[]
(id?)

Попробуйте онлайн! Каждое уравнение 4=3+1+5обозначается как кортеж (4,[3,1,5]). Анонимная функция (id?)берет список таких кортежей и возвращает список всех промежуточных результатов.

#является функцией , чтобы найти неподвижную точку данной функции eи начальное значение x.

Функция ?принимает функцию оценки eи рекурсивно решает каждое уравнение. foldl1(\a b->e#(e#a+e#b))sоценивает правую часть уравнения и сохраняет результат m, например, для 4=3+1+5вычисления eval(eval(eval 3 + eval 1) + eval 5), где каждый evalявляется приложением с фиксированной точкой e. Затем функция eval модифицируется, чтобы принять во внимание новое назначение n: (\x->last$m:[e#x|x/=e#n])то же самое, что и \x -> if x == eval n then m else eval x.

Начальная функция оценки - idэто отображение каждого целого числа на себя.


Спасибо Орджану Йохансену за более короткую функцию с фиксированной точкой, экономящую 2 байта!

Laikoni
источник
Хорошая работа! Кстати, вы должны вернуть все промежуточные результаты, чтобы вы могли отказатьсяlast.
Лев
2
(#)e=until((==)=<<e)eили (#)=until=<<((==)=<<)короче.
Эрджан Йохансен,
@ ØrjanJohansen Большое спасибо!
Лайкони
3

ок, 48 байт

a:[];s:{*(a@x;x)^0N}/;f:{a[s@x]:y:{s@x+y}/s'y;y}

Использование: f[5;1 2 3] / 5=1+2+3

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


Если вы не против того , верхнего предела чисел , которые можно использовать, например, только с помощью чисел 0через 998, то следующие суффиксы ( 41 байт ± несколько в зависимости от максимума):

a:!999;s:(a@)/;f:{a[s@x]:y:{s@x+y}/s'y;y}

Объяснение:

; разделяет три определения.

aсловарь / карта чисел В первом случае, это фактический, пустой словарь [], во втором случае это список номеров 0в 998.

sявляется функцией, которая находит «результирующее» число, когда ему присваивается число. /На конце функции означает , что она будет применять себя свой собственный вывод , пока выход не перестанет изменяться.

Последний бит fозначает, что:

f:{                      } /function called f, input number x, list y
                    s'y    /apply s to every number in the list
                   /       /fold through the list
            {s@x+y}        /    sum the two numbers, apply s
   a[s@x]:                 /set the s(x) to map to the final sum
          y:           ;y  /redefine y to be the final sum, then return it
zgrep
источник
3

Python 3, 146 132 130 байт

14 байтов сохранено благодаря @Dada
2 байта сохранено благодаря @ mbomb007

d={}
g=lambda x:d.get(x)and x!=d[x]and g(d[x])or x
def f(t):
 for n,(s,*r)in t:
  for b in r:s=g(g(s)+g(b))
  d[g(n)]=s;yield g(n)

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

Получает входные данные в виде кортежей уравнений [ x = y + z + was (x, (y, z, w))], выходные данные через генератор.

Уриэль
источник
Можете ли вы показать пример вызова, чтобы его можно было проверить?
Лев
1
@Leo добавил TIO.
Уриэль
1
gможет быть написано g=lambda x:d.get(x)and d[x]!=x and g(d[x])or x. И я думаю, что вы можете использовать 1 пробел для отступа вместо 2. Это даст вам [132 байта] ( попробуйте онлайн! ).
Дада
1
@ Дада спасибо!
Уриэль,
1
Нет отступа от полупространства, но другой хитрый трюк использует одну вкладку вместо двух пробелов. Пока отступы различаются, Python рад (вы могли бы, например, использовать пробел и табуляцию как отступы на дополнительных вложенных уровнях). Это может сэкономить вам два байта :)
Лев,