假设我有两个以下类型的Haskell函数,并激活了ExplicitForAll,
f :: forall a. (a -> Int)
g :: forall a. (Int -> a)
在我看来,g
的类型与Int -> (forall a. a)
同构,因为例如g(2)
的类型为forall a. a
。
但是,f
的类型与(forall a. a) -> Int
看起来并不相同。 f
是一个多态函数,它知道在每个输入类型a
上计算什么,在数学中我想它宁可是一族函数;但我不认为它可以处理一个包含所有类型的单个参数。
类型化lambda演算的规则是类型量词分布在函数目标类型上,而不是函数源类型吗?
Haskell中是否存在类型(forall a. a) -> Int
,可能限制为类型类(forall a. SomeClass a => a) -> Int
?它有用吗?
答案 0 :(得分:2)
weird :: (forall a. a) -> Int
是不必要的具体。
undefined
是唯一具有forall a. a
类型的值,因此定义必须为weird _ = someInteger
,这只是const
的限制性更强的版本。
答案 1 :(得分:2)
∀ a .
基本上只是一个额外的隐式参数,或者更确切地说,应该处理与该参数有关的类型约束的规范。例如,
f :: ∀ a . Show a => (a -> Int)
g :: ∀ a . Show a => (Int -> a)
本质上是两个参数的函数,
f' :: ShowDictionary a -> a -> Int
g' :: ShowDictionary a -> Int -> a
甚至是笨蛋,
type GenericReference = Ptr Foreign.C.Types.Void -- this doesn't actually exist
f'' :: (GenericReference -> String) -> GenericReference -> Int
g'' :: (GenericReference -> String) -> Int -> GenericReference
现在,这些只是单态(或弱动态类型)函数。我们可以清楚地使用flip
来获取
f''' :: GenericReference -> (GenericReference -> String) -> Int
g''' :: Int -> (GenericReference -> String) -> GenericReference
后者可以使用任何Int
参数进行部分评估,因此g
确实等同于γ :: Int -> (∀ a . Show a => Int -> a)
。
使用f'''
,将它应用于一些无效指针参数将是灾难的一个方法,因为类型系统无法确保实际传递的类型与{{{ 1}}函数准备处理。
答案 2 :(得分:0)
这是Chi上述评论的副本,它通过将函数解释为逻辑含义(Curry-Howard对应)来解释理论部分:
类型量子可以用箭头交换,如逻辑: 命题
p -> forall a. q(a)
相当于forall a. p -> q(a)
提供的p
不依赖于a
。如果Haskell有存在类型,我们 会有同构(forall a. p(a) -> q) ~ ((exists a. p(a)) -> q)
。它也与产品通勤(forall a. p a, forall a. q a) ~ forall a. (p a, q a)
。总而言之,它更棘手。
我还链接了RankNTypes的规范。它确实强制执行“浮出”类型量词的规则,并定义类型(forall a. SomeClass a => a) -> Int
。