这个问题已经在这里有了答案: 什么是单态性限制? 1个答案 在GHCi中,以下工作非常花哨: 但是尝试从源文件编译它会导致错误: 这是错误,供参考: “由于使用'/ ='而产生的歧义类型变量'a0'阻止了约束'(Eq a0)'的求解。” ...
提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供 中文繁体 英文版本 中英对照 版本,有任何建议请联系yoyou2525@163.com。
我对Haskell中的函数有以下定义。
> q7 :: forall a. forall b. ((a -> b) -> a) -> a
我面临的挑战是要么为此创建一个定义,要么陈述为什么不存在定义。 这是我的想法:
q7
接受a
和b
任何类型。 语句(a -> b) -> a
将通过获取两项并返回后者来实现。 现在,如果我再上一层,我可以返回相同的“ a
”来实现((a -> b) -> a) -> a
a- ((a -> b) -> a) -> a
。 我看到一个问题,在a
和b
可以是任何类型,因此对于每个实例a
,可能a
是不同的类型? 例如,是否可能像((Int -> Bool) -> [Char]) -> Int
? 我可能谋杀了这种语法。 如果任何人有任何提示,或者任何人可以确认或拒绝我的想法,我将不胜感激!
除了使用无限递归或运行时错误,否则无法终止,这是不可能的。
利用理论计算机科学的一些结果,我们可以证明这确实是不可能的。 我不知道是否有更简单的方法来证明这确实是不可能的。
如果有一种方法可以编写这种类型的终止程序,那么通过Curry-Howard对应关系 ,我们将得到逻辑公式((a -> b) -> a) -> a
(在这里,将->
读为“暗示”)是命题直觉逻辑的一个定理。
这种公式被称为皮尔斯定律 ( Peirce's Law) ,并且是直觉逻辑中无法证明的公式的关键示例之一(相比之下,它是经典逻辑中的一个定理)。
作为证明皮尔斯定律不是直觉定理的一种相当容易的方法,可以运行命题直觉逻辑的决策程序,并观察其输出“不是定理”。 通过这样的过程,我们可以在Gentzen的LJ后续演算中搜索无割证明:以这种方式,我们只需要检查有限数量(且很小)的可能证明,并观察到每次尝试均会失败。
假设你有一个功能
pierce :: ((a -> b) -> a) -> a
进口
data Void
来自Data.Void
。
现在我们开始玩游戏。 我们可以将pierce
类型的a
和b
实例化为我们喜欢的任何类型。 让我们定义
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
的唯一方法是应用f
。
pierce f = f _
现在,我们必须提供a- a -> b
类型a -> b
东西。 我们没有一个。 我们不知道b
是什么,所以我们无法利用通常的从b
构造函数开始的技巧来获得节拍。 什么都不能改善我们b
。 所以我们能做的最好的事情就是
pierce f = f (const undefined)
看起来没有什么用。
语句(a-> b)-> a将通过获取两项并返回后者来实现。
您将其与a- a -> b -> a
(也可以写成a -> (b -> a)
混淆。
(a -> b) -> a
是一个函数,它使用单个参数并返回类型a
a的值。 的参数的类型是a -> b
,这意味着它是一个函数,它类型的值a
,并返回类型的值b
。 这与filter
功能没有什么不同(例如):
filter :: (a -> Bool) -> [a] -> [a]
这有两个参数,一个是a- a -> Bool
类型的谓词函数, a -> Bool
是[a]
类型的列表,并通过将每个列表项传递给谓词来返回新的过滤后的[a]
值。
我看到一个问题,其中a和b可以是任何类型,因此对于a的每个实例,a可以是不同的类型吗?
不,如果可以的话,它的名字会不同。 a
可以是任何类型,但是一旦为a
选择一个类型,则该类型签名中的每个a
都代表该类型。 的b
是不同的字母,因此它可以是由不同类型的a
。
因此,对于类型签名((a -> b) -> a) -> a
,您将编写一个带有单个参数的函数(另一个函数)并返回a
。 参数函数的类型为(a -> b) -> a
,这意味着它将a- a -> b
类型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 = ...
但是,对于所有类型a
和b
,要调用f
,都需要将其传递给函数a -> b
b
。 由于您没有可用的此类功能,并且通常无法编写此类功能,因此我认为这是无法实现的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.