在什么意义上是一个功能"定义较少"比另一个?

时间:2018-02-10 01:32:21

标签: haskell recursion

我的意思是,来自definition

  

fix f是函数f

中最不固定的点

换句话说:

  

最不明确的xf x = x

任何 nullary 类型的最小定义值为undefined。这里有一些含糊之处,因为undefined可能意味着"会抛出错误" (更好)或"永远不会终止" (更糟糕的)。正如推理和试验所示,fix (+1)fix pred :: Word似乎都没有接近终止(即使pred 0是一个错误),所以更糟糕的一个"永远不会终止&#34 ;可能总是在这两种选择之间进行选择。 (可以逃脱fix的是无聊的const 1,但稍后就可以了。)

这不是应用fix的有用方法。

应用fix的有用方法是:

fix (\f x -> if x > 7 then f (x - 1) else x)

- 也就是说,使用fix神奇地生成递归函数。 (这永远不会让我惊讶。)这可以被视为在两个函数之间进行选择:\f x -> f (x - 1)\_ x -> x,其中一个函数永远不会评估它的第一个绑定变量。这是一个危险的玩具,因为我们仍然可以通过意外地将>转移到<-到{{1}来获得一个不会终止其域的一半的函数}。

所以,不知何故,这两个函数:

+

- 后者是&#34; 最少定义的&#34;。如果我们眯着眼睛,我们实际上可以认出我们无聊的同事f1 = \f x -> f (x - 1) f2 = \_ x -> x ,只是const&#39; d。

现在,这是违反直觉的。 flip实际上更具容错能力,因此,从某种意义上说,它是为更多输入值定义的,而不是f2。 (特别是,这是让它逃脱f1)无限循环的原因。具体而言,fix是针对f2(f, x)的所有输入f1对定义的。沿着同一条线,(undefined, x)是所有一元函数最容错的。

那么,我现在如何理解定义

问题的一些理由

this answer nearby这种const 1提供了与此问题中提出的直觉不同的直觉。它还强调,为了充分理解,必须转到关于指称语义的外部教程。

我想得到一个答案,要么支持,要么解释这里提出的直觉的错误,而且,如果领域理论真的落后于评论中提出的草书排序,至少包括一些经验法则,允许(但有限的)但实际应用领域理论。我想看到的问题的一个特定部分是fix能函数是否总能在常数函数和约简函数上分解,这些类的定义是什么?功能是。

我的愿望是建立一个实用的,实用的答案,建立有用且安全的fix编码的递归,并辅以可靠的数学推理。

1 个答案:

答案 0 :(得分:6)

在Haskell中,函数是纯粹的。他们接受输入和产量输出。因此,出现了一个自然的问题:那些不会终止的功能呢?

f x = 1 + f x

此函数会将解释器锁定在无限循环中。但在数学上,我们必须说它&#34;返回&#34;某事,或者它不是一个功能。我们称这是特别的&#34;出了问题&#34;重视&#34;底部&#34;值,我们用符号表示它。

因此,从数学上讲,Haskell Int类型包含每个整数,以及一个额外的特殊元素:。我们称之为包含 a&#34;提升的类型&#34;类型,几乎所有你在Haskell中使用的类型都被解除了。 [1] 事实证明,无限循环并不是调用的唯一方法。我们也可以通过&#34;崩溃&#34;其他方面的翻译。您将看到的最常见的方法是undefined,这是一个内置函数,可以通过一般错误来暂停程序。

但还有另一个问题。具体来说,停止问题。如果应该表示无限循环和其他不可预测的问题,那么我们无法在Haskell中编写某些函数。例如,以下伪代码是荒谬的。

doesItHalt :: a -> Bool
doesItHalt ⊥ = False
doesItHalt _ = True

这将检查结果值是否为,这将解决暂停问题。显然,我们不能在Haskell中做到这一点。那么我们可以在Haskell中定义哪些函数?我们可以定义那些与定义性排序有关的单调性。我们将定义为此排序。我们说是定义最少的值,因此对于所有⊥ ⊑ x都是x是部分排序,因此无法比较某些元素。在1 ⊑ 1期间,1 ⊑ 2 2 ⊑ 1并非如此。在纯英语中,我们说1肯定是低于或等同于1(显然;它们是相同的值),但它并不是&{有道理地说1或多或少地定义为2。他们只是......不同的价值观。

在Haskell中,我们只能定义与此排序有关的单调函数。因此,对于所有值ab,如果a ⊑ b然后f a ⊑ f b,我们只能定义函数。我们上面的doesItHalt失败了,例如,⊥ ⊑ "foo"f ⊥ = Falsef "foo" = True。正如我们之前所说,两个完全定义但不相等的值无法比较。所以这个功能无法工作。

简单来说,我们定义这种方式的原因是因为,当我们&#34;检查&#34;一个使用模式匹配的值,它作为一个断言,必须至少定义它足以让我们看到我们匹配的部分。如果不是,那么我们总是获得,因为程序会崩溃。

值得注意的是,在我们讨论fix之前,有部分定义的&#34;&#34;值。例如,1 : ⊥(在Haskell中,我们可以将其写为1 : undefined)是一个列表,其第一个元素已定义,但列表的尾部未定义。从某种意义上说,这个值是'#34;更明确的&#34;而不是一个简单的,因为我们至少可以模式匹配并提取第一个值。所以我们会说⊥ ⊑ (1 : ⊥) ⊑ (1 : [])。因此,我们最终得到了#34;定义的层次结构&#34;。

现在,fix表示它返回定义最少的固定点。函数f的固定点是x的值,x = f x。让我们试试看几个例子,看看我们是否可以弄清楚为什么会这样说。让我们定义一个函数

f 0 = 1
f x = x

这个功能有很多固定点。对于除{0}以外的任何xf x = x。通过我们最少定义的&#34;原则,哪一个会被退回?实际上,f ⊥将返回。如果我们将undefined传递给f,则第一次模式匹配会导致程序崩溃,因为我们正在将未定义的值与0进行比较。因此是一个定点,因为它是最不可能定义的值,它将由fix f返回。在内部,fix通过无限地将函数应用于自身来工作,因此这有一定的意义。应用f (f (f ...))将继续尝试将内部参数与0进行比较,并且永远不会终止。现在让我们尝试不同的功能。

g x = 0

将此函数无限地应用于自身0。事实证明,fix g = 0。为什么在这种情况下返回0而不是?事实证明,无法成为此功能的固定点。 g ⊥ = 0。由于参数从未被检查过,Haskell是一种非严格的语言,g将返回0,即使您传递undefinederror "Oops!"或一些荒谬的无限递归值一个论点。因此,g固定点,即使是提升类型,也是0,因为g 0 = 0。因此,0确实是g中最不明确定义的固定点。

因此,总而言之,我们定义了一个数学框架,以便严格描述某些功能不会终止的概念。 &#34;至少定义&#34;这只是一种非常数学上精确的说法,fix不会对他们的论证中总是严格的函数起作用。如果f ⊥将返回,则fix f也将返回

*大多数答案都是从the wiki page on Denotational Semantics转述并总结出来的。我鼓励阅读该页面以获取更多信息;它的编写对非数学家来说是非常容易理解的,并且非常有用。

[1]一些原始类型未被解除。例如,GHC特定的Int#是一个不包含的整数类型,在某些地方内部使用。