下面是几个简单的函数:
f1 :: () -> ()
f1 () = ()
f2 :: a -> a
f2 a = a
f3 :: a -> (a, a)
f3 a = (a, a)
f4 :: (a, b) -> a
f4 (a, b) = a
所有f1
、f2
和f3
都能够接受()
作为输入。另一方面,当然f4
不能接受()
;f4 ()
是类型错误。
是否有可能从类型理论上描述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 ☹️
当然,同样的单态化也发生在下面。在这种情况下,注解的类型acceptsUnit'
是它的主要类型。
acceptsUnit' :: (() -> a) -> (() -> a)
acceptsUnit' f = let x = f () in f