Haskell 可以使用foldr重写任何递归定义吗?

Haskell 可以使用foldr重写任何递归定义吗?,haskell,functional-programming,fold,Haskell,Functional Programming,Fold,假设我在haskell中有一个通用的递归定义,如下所示: foo a0 a1 ... = base_case foo b0 b1 ... | cond1 = recursive_case_1 | cond2 = recursive_case_2 ... 它总是可以用foldr重写吗?它能被证明吗?在类型理论中,确实是这样的情况,你可以通过依赖模式匹配将所有定义细化为仅使用消除器的定义(一个更强类型的折叠s,列表的泛化折叠) 如@DanielWagne

假设我在haskell中有一个通用的递归定义,如下所示:

foo a0 a1 ... = base_case
foo b0 b1 ...          
    | cond1 = recursive_case_1
    | cond2 = recursive_case_2
    ...

它总是可以用foldr重写吗?它能被证明吗?

在类型理论中,确实是这样的情况,你可以通过依赖模式匹配将所有定义细化为仅使用消除器的定义(一个更强类型的
折叠
s,列表的泛化
折叠


如@DanielWagner在评论中指出的,如果我们逐字解释您的问题,我们可以编写
const value foldr
来实现任何

一个更有趣的问题是,我们是否可以取而代之的是禁止Haskell的一般递归,而只能通过与每个用户定义的数据类型相关联的消除器/反同构来“递归”,这是
foldr
对归纳定义的数据类型的自然概括。这本质上是(高阶)原语递归

当执行此限制时,我们只能将终止函数(消除器)组合在一起。这意味着我们不能再定义非终止函数

作为第一个例子,我们失去了平凡的递归

f x = f x
-- or even
a = a
如前所述,由于语言变得完整

更有趣的是,一般的不动点算子丢失了

fix :: (a -> a) -> a
fix f = f (fix f)
一个更有趣的问题是:我们可以用Haskell表示的全部函数是什么?我们确实失去了所有的非全函数,但我们是否失去了任何一个全函数

可计算性理论指出,由于语言变得完全(不再是非终止),我们甚至在整个片段上也失去了表达能力

证明是一个标准的对角化参数。修复整个片段中的任何程序枚举,这样我们就可以称之为“第
i
-th个程序”。 然后,让
eval i x
作为在自然
x
上运行
i
-th程序作为输入的结果(为简单起见,假设该程序类型正确,并且结果是自然的)。请注意,由于语言是total,因此必须存在一个结果。此外,
eval
可以在不受限制的Haskell语言中实现,因为我们可以用Haskell编写Haskell的解释器(作为练习:-P),这对片段同样有效。然后,我们只需

f n = succ $ eval n n
上面是一个total函数(total函数的组合),可以用Haskell表示,但不能用片段表示。事实上,否则会有一个程序来计算它,比如说
i
-th程序。在这种情况下,我们会

eval i x = f x
对于所有
x
。但是,

eval i i = f i = succ $ eval i i

这是不可能的——矛盾。QED.

微不足道:
foo a0 a1…=const foldr base_case
。更有用的是:并非所有递归都对列表进行操作。这两条评论的共同主题是,当你说“使用
foldr
重写”时,你应该小心你的意思@Daniel Wagner,
const base\u case foldr
?@user3237465当然可以。我真傻!所有这些都不需要公理K。你需要以顺序的形式重写一些函数(比如Berry的
多数
)。是的,如果我没有弄错的话,这些方程只在命题上成立。什么方程?只是普通的函数定义?对于复杂的理论(比如HoTT)——是的,但是对于好的古老的ITT,消除器是天生产生的(比如警句),所有的东西都有定义。这难道不是我们不能枚举全部函数的证据吗?我们首先假设有一种方法,然后构造一个不在枚举中的total函数。@user3237465您可以枚举语言片段中的函数:只需获取片段中的任何有效程序(那些不使用递归的程序,您可以在程序中检查它),并按长度排序,然后按字符串比较排序即可。这提供了一个有效的无限列表。您是对的,最后一个total函数不在枚举中,这意味着它不在语言片段中。仍然感到困惑。所以这个语言片段包含了所有的基本递归函数,而且只有它们,对吗?但是为什么
f
应该出现在语言片段中呢?它是根据
eval
和枚举内容定义的-它是原始递归的吗?无论如何感谢您的解释。@user3237465
f
不在片段中,这就是我们证明的
f
是一个可由Haskell定义(因为它是可计算的)但不属于片段的total函数的示例。基本上,原语递归不能手工编写
f
@user3237465我的意思是:如果您以某种方式将Haskell限制为一种保证终止的语言,并且可以枚举子语言(通常是这样),那么子语言就不能表达Haskell所能表达的全部函数。换句话说:如果你想(有效地)限制一种语言以确保终止,你也必须扔掉一些函数。