合計?それが私の得意です!


18

前書き

Forteは、数値の値を変更するという概念に基づいた非常に特殊な難解な言語です。Forteの数値は定数ではなく変数であるため、LET命令を使用して新しい値を割り当てることができます。

たとえば、実行した後LET 2=4-1に、今から2の値を前提としてい3た値がいつでもあることを意味、2それは代わりで「置き換え」された表現で起動しますが3。これで式(1+1)*2はに評価され9ます。

Forteのこの命令は、情報の保存とフロー制御の両方に使用されます(行には番号が付けられ、番号の値を変更することで実行順序を決定できます)。この課題では、この2番目の側面を扱いません。

チャレンジ

ForteのLET式の簡略化されたサブセット用のインタープリターを作成する必要があります。

入力として、この文法に続く一連の行を受け取ります。

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

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

注:この文法は、行番号、LET、および括弧(常に必須)がないため、有効なForteではありません。

つまり、合計の計算と数値への値の割り当てのみを処理する必要があります。括弧は入力に存在せず、各式は左から右に評価する必要があります:部分的な結果は再定義の影響を受けることに注意してください!

数値は常に、使用している言語のネイティブ整数型の制限(または2 ^ 32のいずれか大きい方)までの負でない整数になります。

各行について、式の結果を出力し、この結果を最初の数値の(場合によっては再割り当てされた)値に割り当てる必要があります。これは、後続の行の解釈方法に影響します。

これはで、最短のコード(バイト単位)が勝ちです!

その他の規則

  • 入力形式は柔軟です。たとえば、改行を含む単一の文字列、文字列のリスト、数値のリストのリストを使用できます...入力。
  • 関数、完全なプログラム、またはソリューションをサブミットして、REPL環境で実行し、各行に対して1回呼び出すことができます。
  • 標準的な抜け穴は禁止されています。特に、コード内で外部の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有効な番号は?
orlp

@orlp 0は有効です(「数値は常に非負の整数です」)
レオ

算術演算子を受け入れる必要がありますか?
バッカスビール

@bacchusbealeいいえ、総計です。
レオ

特定の最大数はありますか、それとも言語のネイティブ整数型と同じ大きさですか?また、数値のリストを返すのは無効な出力になりますが、そのうちの1つは結果です。(どの番号がどの番号に行くかなどの辞書/マップの印刷など)
-zgrep

回答:


4

ゼリー、28バイト

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

オンラインでお試しください!

これは、標準入力から入力を取得するのが難しいと思われる数少ないJellyプログラムの1つです。これは完全なプログラムです(関数の作成はもっと短かったはずですが、PPCGルールによって禁止されています。2回目に正しく実行されないためです)。入力形式は次のようになります。

[[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には変数が1つしかありません)。

ヘルパー関数 2Ŀ(1つの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}

通常、このコンテキストで実行する場合、最初のコマンドライン引数を提供しますが、1つはありません(標準入力から入力を取得しています)ので、null文字列を提供する代替モードで実行されます。レジスタを初期化する必要がある(0クラッシュするのデフォルト値からy)とは、ユーザーの入力を暗黙的に言及できないことを意味します。つまり、標準入力(Ɠ)から取得するのと同じくらい安価です。コマンドライン引数(³または)、および代替の使用方法にアクセスできるということは、入力の異常な(Jellyの)形式が実際には1バイト短いことを意味します。

これは改善可能である可能性があります。/ / の使用がないことを考えると、Jellyを理解している限り、2行目⁸Ǥ;は単に2行目;@Çが同等である必要がある理由をまだ理解できていませんが、後者は何らかの理由でクラッシュします。同様に、バイトを失うことなくプログラムを再配置する他のさまざまな方法があるため、物事を少し短くする方法を見逃した可能性があります。µðø

ちなみに、最後の行をに変更する;と、プログラムの内部動作を興味深い外観で見ることができます。これは、の戻り値によって暗黙的に出力される「レジスタの履歴」を出力するためです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数値間のマッピングを保存します。
関数(subfは、入力マップ(または、番号にマップされていない場合は入力)がマップされる番号を返し$h{$a=pop}ます。入力がマップされる番号を取得します。なしの場合、のおかげで//$a、の値($b=$h{$a=pop}//$a)は入力($a)です。この値は、無限ループしない入力そのものではないことを確認します(!=$a)。次に、f入力を再帰的に呼び出すか、返します。
メインプログラムは、2つのステップから成る:
- 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 1バイトを節約するためにカリー化された計算と割り当てを実行し、2番目の呼び出しは計算された値を返します。


3

Haskell116113108106バイト

(#)=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はtupleとして表記され(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、各整数をそれ自体にマッピングします。


短いフィックスポイント関数のØrjanJohansenに感謝し、2バイトを節約しました!


良くやった!ちなみに、すべての中間結果を返す必要があるため、ドロップできますlast.
レオ

2
(#)e=until((==)=<<e)eまたは(#)=until=<<((==)=<<)より短いです。
Ørjanヨハンセン

@ØrjanJohansenありがとうございます!
ライコニ

3

OK、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}

説明:

; 3つの定義を分離します。

a数字の辞書/地図です。最初のケースでは、それは実際、空の辞書だ[]後者の場合には、それは数字のリストだ、0998

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

3

Python 3、146 132 130バイト

@Dadaのおかげで14バイト節約
@ mbomb007のおかげで2バイト節約

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。そして、2の代わりに1つのスペースを使用してインデントできると思います。これで[132バイト]に到達するはずです(オンラインで試してみてください!)。
ダダ

1
@ダダありがとう!残念なことに、半角インデントがありません:P
Uriel

1
半角スペースのインデントはありませんが、2つのスペースの代わりに1つのタブを使用する別の巧妙なトリックがあります。インデントが異なる限り、Pythonは満足です(たとえば、追加のネストレベルでインデントとしてspace-tabとtab-spaceを使用できます)。これにより、2バイト節約できます:)
レオ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.