教堂减法


13

教堂减法

Lambda演算一直是我的迷恋,并且将函数相互传递的新出现的行为令人愉快地复杂。教堂数字是自然数的表示,该自然数是由函数的重复应用构成的(通常是常数的一元加法)。例如,数字零返回x并“忽略”输入函数,一个为f(x),两个为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然后将第二个函数应用于x可以完成加法运算:

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

加法相对容易理解。但是,对于新手来说,想像一下教堂编码数字系统中的减法可能是不可想象的。取消应用功能可能意味着什么?

挑战

在教堂编码数字系统中实现减法功能。如果结果将大于零,则减法执行monus运算,并且不应用函数n时间,否则将大于零。这是代码高尔夫球,因此最短的代码获胜。

输入值

您选择的语言中已编码的两个教堂数字。输入可以是位置输入或咖喱输入。为了证明这些是真实的教堂数字,它们将必须具有任何功能并反复应用它们(add1在示例中给出,但可能是add25mult7或任何其他一元函数)。

输出量

教堂数字。应当注意的是,如果m < n然后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的。)
Neil

1
我不确定“输入可以是位置输入还是咖喱输入”的意思。是否可以将main函数定义为lambda m,n,f:apply f m-n times(甚至lambda m,n,f,x:apply f m-n times to x)而不是lambda m,n:lambda f:...?还是这仅适用于两个输入mn
xnor19

此外,我们可以接受的参数mn在另外的顺序?这将有助于咖喱。
xnor19

@xnor,只要您可以证明它减去两个教堂数字,就可以随心所欲地输入。
瑞安·谢弗

Answers:


9

Haskell,35个字节

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

在线尝试!

再说说rs是的邱奇数mn。我们希望r%sf m-n时间应用于某个初始值x。我们首先生成无限列表

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

然后使用s(x:)前缀的n副本x,即,将每个值n索引右移:

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

然后,我们m直接将计算为r(+1)0,并将m该列表的'th元素作为!!r(+1)0。无需索引的解决方案可以代替head$r tail$...,即删除第一个元素m时间,然后获取第一个元素,但是索引语法要短得多。

请注意,经典解决方案无法在没有扩展的Haskell中使用,因为其强类型不能代表其前身操作。


3

Python 2中82 80个字节

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

在线尝试!

尼克·肯尼迪Nick Kennedy)发送2个字节,注意到不需要的一对括号。

实现减号的匿名函数。

通常,这只是压缩在Wikipedia页面上找到的定义。还不像我真正了解代码。但是有趣!


基于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:不错的“把戏”!
Chas Brown

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答案,而不仅仅是查看gists的实现。您是否考虑过像其他答案一样使用eval来进一步打高尔夫球?
瑞安·谢弗

@RyanSchaefer当我看到另一个答案时,我确实检查了eval / replace东西,但实际上这里要长2个字节,要替换5个lambda。不幸的是,Python在定义函数和字符串操作方面都非常罗word。而且它缺少内置的“撰写”功能,可以节省一层lambda。
xnor19

2

C ++(clang),112字节

#define L(x,y)[&](auto x){return y;}
auto m=L(u,L(v,v(L(n,L(f,L(x,n(L(g,L(h,h(g(f)))))(L(u,x))(L(u,u))))))(u)));

在线尝试!

这是迄今为止我编写过的最不可理解的C ++代码。也就是说,我认为取消对此代码的处理只会使它变得更糟。


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时间和第二个功能g时间。然后,我们应用逆函数([f,[g,a]])=>[g(x),a] f时间。这跳过了g第二阶段并执行f-g根据需要第一阶段。然后保留提取最终值。

元组当然可以转换为lambda函数,从而产生以下表达式:

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中的高阶函数是使用副词和连词实现的。此处的教堂数字是副词的gerund形式,是通过组合“连词的力量”(反复应用动词)和整数而形成的。以下动词c(用于“创建”)使用J的原子表示将整数转换为这样的gerund:

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

我们的“减号”运算符(是一个连词)从左边减去右边的gerund教堂数字。但是,它不假定教堂数字的任何特定实现,包括我们c动词中的数字。取而代之的是,它依赖于一般定义,并通过将undund反转每个5!:0动词教堂数字,然后将其应用到增量动词上>:,然后将应用到0 从而将其转换为副词。

然后,它减去并取最大值0,然后求出c最终结果:一个新的gerund教堂数字。


1

Wolfram语言(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][#]&

(未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]]    *)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.