教会の減算


12

教会の減算

ラムダ計算は常に私の魅力であり、関数を相互に渡す緊急行動は非常に複雑です。教会の数字は、関数の繰り返しの適用(通常は定数の単項加算)から構築された自然数の表現です。たとえば、数値ゼロはxを返し、入力関数を「無視」します。1つはf(x)、2つは次のf(f(x))ようになります。

ident = lambda x: x
zero = lambda f: ident
succ = lambda n: lambda f: lambda x: f(n(f)(x))
one = succ(zero)
add1 = lambda x: x + 1
to_int = lambda f: f(add1)(0)
print(to_int(one))
>>> 1

このことから、最初の関数をxに適用し、次に2番目の関数をxに適用することで加算が達成されることが簡単にわかります。

add = lambda m: lambda n: lambda f: lambda x: n(f)(m(f)(x))
print(to_int(add(one)(two)))
>>> 3

追加は比較的簡単です。しかし、新参者にとって、教会で符号化された数値システムで減算がどのように見えるかを考えることは考えられないかもしれません。関数の適用を解除するとどうなりますか?

チャレンジ

教会でエンコードされた数字システムに減算機能を実装します。減算がmonus操作を実行しn、結果がゼロまたはゼロより大きい場合、関数時間を適用しない場合。これはコードゴルフなので、最短のコードが優先されます。

入力

選択した言語でエンコードされた2つの教会の数字。入力は定位置またはカリー化できます。これらは真の教会の数字を証明するために、彼らは、任意の機能を取り込み、繰り返しそれらを適用する必要があります(add1例に示されているが、それは可能性がありadd25mult7または任意の他の単項機能。)

出力

教会の数字。m < nthen m - nが恒等関数と常に同じであることに注意してください。

例:

minus(two)(one) = one
minus(one)(two) = zero
...

許容範囲:

minus(two, one) = one
minus(one, two) = zero

クレジット:

このgithubは、Church Numeralsのpython実装を提供するための要点です。


1
(要点のコメントは間違っています; もちろんexp(m, n)計算m^nします。)
ニール

1
「入力は定位置またはカリー化できる」とはどういう意味かわかりません。main関数をlambda m,n,f:apply f m-n timeslambda m,n,f,x:apply f m-n times to xではなく)として定義しても大丈夫lambda m,n:lambda f:...ですか?それともこれは単に2つの入力に適用されないmn
xnor

また、引数mn他の順序で取りますか?これはカレーに役立ちます。
xnor

@xnorは、2つの教会の数字を差し引くことを証明できれば、とにかく入力を行うことができます。
ライアンシェーファー

回答:


9

Haskell、35バイト

(r%s)f x=s(x:)(iterate f x)!!r(+1)0

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

と言うrs、教会のエンコーディングmnです。時間を初期値r%sに適用したい。最初に無限リストを生成しますf m-nx

iterate f x = [x, f x, f (f x), f (f (f x)), ...]

次に、のコピーのs(x:)先頭に使用します。つまり、各値のインデックスを右にシフトします。nxn

s(x:)(iterate f x) = [x, x, x, ...,  x, f x, f (f x), f (f (f x)), ...]

次に、mとして直接計算し、そのリストの '番目の要素をとしてr(+1)0取ります。代わりに、インデックスを作成しないソリューションでは、最初の要素をドロップしてから最初の要素を取得するという方法を使用できますが、インデックスの構文ははるかに短くなります。m!!r(+1)0head$r tail$...m

ことに注意してください 従来のソリューションは拡張機能なしではHaskellでは機能しない、強力な型付けが先行操作を表すことができないためです。


3

パイソン282の 80バイト

eval('!u:!v:v(!n:!f:!x:n(!g:!h:h(g(f)))(!u:x)(!u:u))(u)'.replace('!','lambda '))

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

ニックケネディへの2バイトの送信は、不要なペアのペアに注目します。

マイナスを実装する匿名関数。

ほとんどの場合、これはウィキペディアのページにある定義を圧縮するだけです。まだコードを本当に理解しているわけではありません。でも面白い!


OPが述べた要点に基づいて、!u:!v:v(!n:!f:!x:n(!g:!h:h(g(f)))(!y:x)(!x:x))(u)2バイトを節約するようですが、私はコードを本当に理解していません!
ニックケネディ

@NickKennedy gettingsharper.de/2012/08/30/...あなたが興味を持っている場合
ライアン・シェーファー

@Ryan Schaefer:素敵な「トリック」!
チャスブラウン

3

Python 2、77バイト

lambda r,s:s(lambda r:lambda f:lambda x:r(lambda(_,x):(x,f(x)))((x,x))[0])(r)

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

繰り返しごとに以前の値を追跡し、最後に出力することにより、教会の減少を行います。コードの長さの39%は"lambda"'...


いいね!私は要点の実装だけでなく、ゴルフをしたpythonの回答を待っていました。これをさらにゴルフするために、他の答えのようにevalを使用することを考えましたか?
ライアンシェーファー

@RyanSchaefer私は他の答えを見たときにeval / replaceをチェックしましたが、実際にはここで5バイトのラムダで置き換えて2バイト長くなっています。Pythonは、残念ながら、関数の定義と文字列操作の両方で非常に冗長です。また、ラムダの層を節約する組み込みの「構成」がありません。
xnor


2

アンダーロード、37バイト

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

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

内部(((!())~):*^(~!:(:)~*(*)*)~^^!)pred関数であり、ペアを介して実装されます:

(               ( start pred function )!
  (
    (!())~      ( push zero below argument )!
  ):*^          ( do that twice )!

  (             ( start pair-increasing function )!
    ~!          ( remove second argument)!
    :           ( duplicate first argument )!
    (:)~*(*)*   ( increment first return value )!
  )
  ~^^           ( run pair-increasing function n times )
  !             ( remove first in returned pair )!
)


1

JavaScript(Node.js)87 85 81 76 74バイト

f=>g=>h=>x=>f(([x,[g,a]])=>[g(x),a])([x,g(a=>[x=>x,a])(f(a=>[h,a])())])[0]

オンラインでお試しください!受賞するつもりはありませんが、別のアプローチを試してみようと思いました。

a=>[h,a]は適用される段階ですがh、適用されa=>[x=>x,a]ない段階ですh。最初の関数f時間と2番目の関数g時間を適用します。次に、逆関数([f,[g,a]])=>[g(x),a] f時間を適用します。これは、g2番目の段階をスキップして実行しますf-g必要に応じて最初の段階がれます。その後、最終値を抽出するために残ります。

タプルはもちろんラムダ関数に変換でき、次の式になります。

f=>g=>h=>x=>f(e=>e(x=>d=>d(g=>a=>e=>e(g(x))(a))))(e=>e(x)(g(a=>e=>e(x=>x)(a))(f(a=>e=>e(h)(a))())))(x=>a=>x)

1

J、56バイト

c=:3 :0
t=.^:y
5!:1<'t'
)
m=.2 :'c 0>.(>:u 5!:0->:v 5!:0)0'

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

注:TIOカウントの-3バイトm=.

Jの高階関数は、副詞と接続詞を使用して実現されます。ここで、教会の数字は、動詞を繰り返す「力」と整数を組み合わせることによって形成される副詞の動名詞形です。次の動詞c(「作成」)は、Jの原子表現を使用して整数をそのような動名詞に変換します。

c=:3 :0
t=.^:y
5!:1<'t'
)

「マイナス」演算子(接続詞)は、左から右のガーンド教会の数字を引きます。しかし、私たちのc動詞からのものを含め、教会の数字の特定の実装を想定していません。代わりに、一般的な定義に依存し、各動名詞教会の数字をで反転して副詞に戻し、5!:0その副詞を増分動詞>:に適用し、それを0に適用します。

次に、減算して0で最大値cを取り、最終結果である新しいガーンド教会の数字を取得するために適用します。


1

Wolfram Language(Mathematica)55 48 47 39バイト(33文字)

#2[(fx#[g#@g@f&][x&][#&])&]@#&

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

記号は0xF4A1で、の右向き矢印を示すMathematicaの特別なコードポイントです\[Function]詳細については、こちらご覧ください。これはMathematicaフロントエンドでのコードの外観です:

ここに画像の説明を入力してください

我々はそれを行うことができます40バイト/ 32文字測定方式に応じて短くなる場合があります:#2[n⟼f⟼x⟼n[g⟼#@g@f&][x&][#&]]@#&

ゴルフされていないバージョンは、predの古典的な定義の文字通りの翻訳です:

pred = n \[Function] f \[Function] x \[Function] n[g \[Function] h \[Function] h[g[f]]][u \[Function] x][u \[Function] u];
subtract[m_, n_] := n[pred][m]

Mathematicaフロントエンドでは次のようになります:

ここに画像の説明を入力してください

この減算関数は、

c@0=#& &;c@n_=#@*c[n-1][#]&

(UN-golfed: c[0] = Identity &; c[n_] = Function[a, a@*c[n-1][a]]

私たちが持っているように

Table[c[n][f][x], {n, 0, 6}]
(*    {x, f[x], f[f[x]], f[f[f[x]]], f[f[f[f[x]]]], f[f[f[f[f[x]]]]], f[f[f[f[f[f[x]]]]]]}    *)

そして

subtract[c[7],c[5]][f][x]
(*    f[f[x]]    *)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.