Sim*_*n C 9 polymorphism haskell type-theory hindley-milner system-f
下面是几个简单的函数:
f1 :: () -> ()
f1 () = ()
f2 :: a -> a
f2 a = a
f3 :: a -> (a, a)
f3 a = (a, a)
f4 :: (a, b) -> a
f4 (a, b) = a
Run Code Online (Sandbox Code Playgroud)
所有的f1,f2以及f3能够接受()为输入。另一方面,当然f4不能接受();f4 ()是类型错误。
是否有可能TYPE-理论上刻画了什么f1,f2以及f3有什么共同点?具体而言,是有可能定义一个acceptsUnit函数,以使得acceptsUnit f1,acceptsUnit f2和acceptsUnit f3是公类型的,但acceptsUnit f4是一种类型的错误-和不具有其他的效果?
下面完成了部分工作,但将其输入单态化(在 Haskell 中,我在 Hindley-Milner 中收集),因此其效果不仅仅是简单地断言其输入可以接受():
acceptsUnit :: (() -> a) -> (() -> a)
acceptsUnit = id
-- acceptsUnit f4 ~> error
-- acceptsUnit f3 'a' ~> error ??
Run Code Online (Sandbox Code Playgroud)
当然,同样的单态化发生在下面。在这种情况下,被注释的类型acceptsUnit'是它的主要类型。
acceptsUnit' :: (() -> a) -> (() -> a)
acceptsUnit' f = let x = f () in f
Run Code Online (Sandbox Code Playgroud)
从理论上来说,很容易描述f1、f2、 和f3但没有f4共同点的特征。用 Hindley-Milner 的语言来说,前三个具有可以专门化为以下形式的多型体的多型体:
forall a1...an. () -> tau
Run Code Online (Sandbox Code Playgroud)
对于 n >= 0 且 tau 为任意单型。第四个不行。
您可以编写一个接受前三个作为参数但拒绝第四个的函数吗?好吧,这取决于您使用的类型系统以及您构建函数的自由度。在通常的 Hindley-Milner 和/或标准 Haskell 类型系统中,如果您可以自由地将候选函数的两个副本传递给接受函数,则以下操作将起作用:
acceptsUnit :: (() -> a) -> (b -> c) -> (b -> c)
acceptsUnit = flip const
f1 :: () -> ()
f1 () = ()
f2 :: a -> a
f2 a = a
f3 :: a -> (a, a)
f3 a = (a, a)
f4 :: (a, b) -> a
f4 (a, b) = a
main = do
print $ acceptsUnit f1 f1 ()
print $ acceptsUnit f2 f2 10
print $ acceptsUnit f3 f3 10
-- print $ acceptsUnit f4 f4 -- type error
Run Code Online (Sandbox Code Playgroud)
这可能是您使用标准 Haskell 所能做的最好的事情(也可能是您使用 Haskell 加上 GHC 类型系统扩展所能做的最好的事情,或者现在有人可能已经找到了一些东西)。
如果您可以使用自己的打字规则自由定义自己的打字系统,那么天空就是极限。