隐式编程

隐式（tacit）编程，或称为函数级编程，是一种编程范型，也叫做无点（point-free）样式。其中函数定义不标示所要运算的被称为“点”的参数，转而函数定义只是其他函数的复合，比如那些操纵参数的组合子。隐式编程有着理论价值，因为严格的使用复合导致程序适配于。隐式编程是特定编程语言的天然样式，这包括了APL的一些现代实现和方言，和串接式语言比如Forth。由于缺少参数命名，认为这种风格导致了不必要的晦涩难懂的人，给它起了个绰号叫做“无意义”（pointless）风格。
APL语言家族.
在一些APL方言中，允许将函数组合入服从几个规则的“列车”（train）；这允许建立复杂的派生函数，而不需要显式指定任何参数；实现了列车的APL方言包括：J语言、Dyalog APL、dzaima/APL、ngn/apl和NARS2000。
J语言.
在J语言中，下列在一个数值的列表（阵列）上计算平均值的函数采用了一种无参数样式代码：
<syntaxhighlight lang=j>avg=: +/ % #</syntaxhighlight>
codice_1通过将求和（codice_2）插入（codice_3）到一个阵列的所有元素之间来计算它们的合计值。codice_4总计一个阵列的元素数目。codice_5用codice_1这个阵列的结果值除以codice_4这个阵列的结果值。
欧拉公式formula_1可隐式表达为：
<syntaxhighlight lang=j>
cos =: 2 o. ]
sin =: 1 o. ]
Euler =: ^@j. = cos j. sin
</syntaxhighlight>
这里定义的函数codice_8在任何输入值上都恒等于codice_9，即这个等式永远为真。其中用到了一些原语（primitive）函数：codice_10表示全局定义；codice_11表示圆函数，由左侧名词参数选择具体的函数；codice_12不变动的返回右侧名词参数；codice_13的一元定义为指数函数；codice_14的一元定义为虚数单位codice_15乘以右侧参数codice_16，而它的二元定义为codice_17，即组合左侧参数codice_18和右侧参数codice_16成为复数，而二者分别是其实部和虚部；codice_20表示数学函数复合；codice_21是等于布尔运算，两侧参数相等返回codice_9而不等返回codice_23。
Dyalog APL.
上述相同的隐式计算用APL的现代版本Dyalog APL表达为：
<syntaxhighlight lang=APL>
avg ← +⌿ ÷ ≢
cos ← 2 ○ ⊢
sin ← 1 ○ ⊢
j ← {⍺←0 ⋄ ⍺+0j1×⍵} ⍝ j函数的定义不是隐式的
Euler ← *∘j = cos j sin
</syntaxhighlight>
这里采用定义了codice_24函数，其中在codice_25与codice_26之间由codice_27分隔的是守卫的表达式序列（这里只有表达式），codice_28指示左参数而codice_29指示右参数，codice_30指示一元定义需要的缺省左参数。
Unix管道.
在Unix shell脚本中，命令是从标准输入接收数据并发送结果至标准输出的。例如：
<syntaxhighlight lang="bash">
sort | uniq -c | sort -rn
</syntaxhighlight>
可以视为一个隐式或无点复合，它返回它的每个参数的计数和这些参数，并按照这个计数的递减次序来排序。命令codice_31和codice_32相当于函数，而codice_33和codice_34是控制这些函数的选项，但是不提及参数。管道codice_35相当于函数复合算子。下面是其用例：
<syntaxhighlight lang="console">
$ echo '2 4 3 1 3 12 2' | xargs -n1 | sort | uniq -c | sort -rn
</syntaxhighlight>
Python.
如下Python代码是对应上节示例中Unix管道中命令的函数定义和一序列的运算：
<syntaxhighlight lang="python">
def sort(argv):
def uniq_c(argv):
def sort_rn(argv):
a = 4, 3, 1, 3, 12, 2
b = sort_rn(uniq_c(sort(a))) 
</syntaxhighlight>
这里的codice_36由于codice_37所采用的实现方法不再依赖于它而没有存在必要，只是为了与上节Unix示例保持一致。
基于标准库的函数式编程工具codice_38中的函数codice_39和归约函数codice_40，这个例子可以写为无点样式的没有参数的一序列函数的复合：
<syntaxhighlight lang="python">
from functools import partial, reduce
def compose(*func_list):
pipeline = compose(sort, uniq_c, sort_rn)
c = pipeline(a)
assert b == c
</syntaxhighlight>
jq语言.
jq是面向JSON的纯函数式编程语言，它使用codice_35符号来连接过滤器形成流水线。例如：
<syntaxhighlight lang="console">
$ echo '[1,2]' | jq 'add/length'
1.5
$ jq -n '[1,2] | add/length'
1.5
</syntaxhighlight>
这里jq内的JSON阵列codice_42是求值为阵列的一个jq过滤器。尽管类似于Unix流水线，jq流水线允许将到来数据，如同并行的发送到在codice_35右手端的多于一个接收者。
上述Python章节中例子，在jq中等价的无点风格定义为：
<syntaxhighlight lang="python">
def uniq_c:
def sort_nr:
4, 3, 1, 3, 12, 2 
</syntaxhighlight>
将这段代码保存入codice_44文件中，下面是其执行结果：
<syntaxhighlight lang="console">
$ jq -nc -f ./pipeline.jq 
</syntaxhighlight>
函数式编程语言.
下面是采用纯函数式编程语言Haskell的一个简单例子，它在一个列表上作合计的函数。编程者可以使用“有点”（pointed）也称为值级编程的方法，而递归的定义这个合计为：
<syntaxhighlight lang="haskell">
sum (x:xs) = x + sum xs
sum [] = 0
</syntaxhighlight>
这是一种折叠（fold）运算，编程者可以将它改写为：
<syntaxhighlight lang="haskell">
sum xs = foldr (+) 0 xs
</syntaxhighlight>
这里的参数是不必须的，进而将它改写成如下“无点”也称为函数级编程的样式：
<syntaxhighlight lang="haskell">
sum = foldr (+) 0
</syntaxhighlight>
Haskell拥有算子：
<syntaxhighlight lang="haskell">
(.) :: (b -> c) -> (a -> b) -> a -> c
</syntaxhighlight>
它有如下性质：
<syntaxhighlight lang="haskell">
f . g = f(g)
f . g = (.) f g
f . g = (f .) g 
f . g = (. g) f
</syntaxhighlight>
这里的codice_45和codice_46，分别称为codice_47的左“节”（section）和右“节”，是对这个中缀算子的左侧和右侧。codice_48，本文采用后者形式。正如前面所说，在“无点”中的点（point）指称参数，而非不使用点号（dot），这是常见误解。
下面的例子展示其用法，给出一个函数codice_49的定义：
<syntaxhighlight lang="haskell">
p x y z = f (g x y) z
</syntaxhighlight>
经过如下推导：
<syntaxhighlight lang="haskell">
p = \x -> \y -> \z -> f (g x y) z
</syntaxhighlight>
它可以归约成无点的等价定义：
<syntaxhighlight lang="haskell">
p = ((.) f) . g
</syntaxhighlight>
下面是一个复杂一些的例子，这里的codice_50是一个先做映射（map）再加过滤器（filter）的函数，它接受一个列表codice_51，向它应用一个函数codice_52，接着基于一个准则codice_53来过滤元素：
<syntaxhighlight lang="haskell">
mf criteria operator list = filter criteria (map operator list)
</syntaxhighlight>
经过如下推导： 
<syntaxhighlight lang="haskell">
mf = \x -> \y -> \z -> filter x (map y z)
</syntaxhighlight>
codice_50可以表达为无点样式：
<syntaxhighlight lang="haskell">
mf = (. map) . (.) . filter
</syntaxhighlight>
串接式编程语言.
在串接式编程语言和面向堆栈编程语言中，无点方法也很常用。例如，计算斐波那契数的过程，在Unix的dc命令中可实现为：
<syntaxhighlight>
[d 1- lFx r 2- lFx +sG lFx
</syntaxhighlight>
下面是其用例：
<syntaxhighlight lang="console">
$ echo 7 | dc -e '? [d 1- lFx r 2- lFx +sG lFx p'
13
</syntaxhighlight>
在Factor中可与其等价的实现为：
<syntaxhighlight lang="factor">
</syntaxhighlight>
在这两个例子中，递归调用函数的参数在堆栈中而没有被显式的命名。