
[英]How to write "twice" so it can accept "swap" without restricting their type
[英]Characterizing the type of functions that can accept `()` as input (without monomorphizing)
下面是几个简单的函数:
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
很容易从类型理论上描述f1
、 f2
和f3
而不是f4
的共同点。 在 Hindley-Milner 的语言中,前三个具有可以特化为以下形式的多型的多型:
forall a1...an. () -> tau
对于 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
这可能是您使用标准 Haskell 所能做的最好的事情(也可能是您使用 Haskell 加上 GHC 类型系统扩展所能做的最好的事情,或者现在有人会发现一些东西)。
如果您可以使用自己的打字规则自由定义自己的打字系统,那么天空就是极限。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.