Haskell中有此lambda语句的有效定义吗?

时间:2018-11-14 17:34:56

标签: haskell typing lambda-calculus

我对Haskell中的函数有以下定义。

> q7 :: forall a. forall b. ((a -> b) -> a) -> a

我面临的挑战是要么为其创建定义,要么说明为什么不存在定义。这是我的想法:

q7接受ab的任何类型。语句(a -> b) -> a可以通过采用两项并返回后者来实现。现在,如果我再上一层,我可以返回相同的“ a”来完成((a -> b) -> a) -> a。我看到一个问题,其中ab可以是任何类型,因此对于a的每个实例,a可以是不同的类型吗?例如,可能是类似((Int -> Bool) -> [Char]) -> Int的东西吗?我可能谋杀了这种语法。如果任何人有任何提示,或者任何人可以确认或拒绝我的想法,我将不胜感激!

3 个答案:

答案 0 :(得分:5)

除了使用无限递归或运行时错误外,否则不可能终止。

我们可以利用理论计算机科学的一些结果证明这确实是不可能的。我不知道是否有更简单的方法来证明这确实是不可能的。

如果有一种通过Curry-Howard correspondence编写这种类型的终止程序的方法,我们将得到逻辑公式((a -> b) -> a) -> a(在这里,将->读作“隐含”) )是命题直觉逻辑定理。

这种公式被称为Peirce's Law,并且是直觉逻辑中无法证明的公式的关键示例之一(相对而言,是经典逻辑中的一个定理)

作为证明皮尔士定律不是直觉定理的一种相当容易的方法,可以运行命题直觉逻辑的决策程序,并观察其输出“不是定理”。通过这种方法,我们可以在Gentzen的LJ后续演算中搜索无割证明:这样,我们只需要检查有限(且很小)的可能证明,并观察每次尝试都将失败。

答案 1 :(得分:3)

假设您有一个功能

pierce :: ((a -> b) -> a) -> a

导入

data Void

来自Data.Void

现在我们可以玩游戏了。我们可以将a类型的bpierce实例化为我们喜欢的任何形式。我们来定义

type A p = Either p (p -> Void)

并实例化

a ~ A p
b ~ Void

所以

pierce :: ((A p -> Void) -> A p) -> A p

让我们写一个助手:

noNegate :: forall p r. (A p -> Void) -> r
noNegate apv = absurd (n m)
  where
    m :: p -> Void
    m = apv . Left

    n :: (p -> Void) -> Void
    n = apv . Right

现在我们可以杀人了:

lem :: Either p (p -> Void)
lem = pierce noNegate

如果存在此功能,那将非常奇怪。

lem @Void = Right id
lem @() = Left ()
lem @Int = Left ... -- some integer, somehow

此功能的行为看起来很奇怪,因为它违反了Haskell函数无法做到的参数化,但是事情只会变得更糟。

有可能(但有点烦人)将任意图灵机编码为Haskell类型。并且有可能设计一个表示特定Turing机器将停止的证明的类型(基本上是类型索引的执行跟踪)。在这样的跟踪类型上应用lem将解决暂停问题。


由于Haskell的懒惰,一些“不可能的”功能被证明是有用的,尽管是局部的。例如,

fix :: (a -> a) -> a

在形式上是荒谬的,因为fix id声称可以为您提供任何您想要的东西。 pierce不是这样的功能。让我们尝试编写它:

pierce :: ((a -> b) -> a) -> a
pierce f = _

右边必须显示什么?制作a only 方法是应用f

pierce f = f _

我们现在必须提供a -> b类型的东西。我们没有一个。我们不知道什么是b ,因此我们无法利用从某个b构造函数开始的惯用技巧来获得成功。没有任何东西可以改善我们的b。所以我们能做的最好的就是

pierce f = f (const undefined)

看起来没有什么用。

答案 2 :(得分:1)

  

语句(a-> b)-> a将通过获取两项并返回后者来实现。

您将其与a -> b -> a(也可以写为a -> (b -> a)混淆。这是不一样的。

(a -> b) -> a是一个具有单个参数并返回类型a的值的函数。该参数的类型为a -> b,这意味着它是一个函数,其值类型为a,并且返回值类型为b。这与filter函数没有什么不同:

filter :: (a -> Bool) -> [a] -> [a]

这需要两个参数,类型为a -> Bool的谓词函数和类型为[a]的列表,并通过将每个列表项传递给谓词来返回新的过滤后的[a]值。 / p>


  

我看到一个问题,因为a和b可以是任何类型,所以对于a的每个实例,a可以是不同的类型吗?

否,如果可以的话,将使用其他名称。 a可以是任何类型,但是一旦为a选择了一个类型,则该类型签名中的每个a都代表该类型。 b是一个不同的字母,因此它可以是与a不同的类型。


因此,对于类型签名((a -> b) -> a) -> a,您将编写一个带有单个参数的函数(另一个函数)并返回一个a。参数函数的类型为(a -> b) -> a,这意味着它将类型为a -> b的函数作为参数并返回a

func :: ((a -> b) -> a) -> a
func f = ...

参数f(如果被调用)将返回一个a,然后您可以从func返回该参数:

func :: ((a -> b) -> a) -> a
func f = f x
  where x :: a -> b
        x = ...

但是,要调用f,您需要为所有类型a -> ba传递一个函数b。由于您没有可用的此类功能,并且通常无法编写此类功能,因此我认为这是无法实现的。