繁体   English   中英

为什么这个Haskell代码编译?

[英]Why does this Haskell code compile?

鉴于:

uncurry :: (a-> b -> c) -> (a,b) -> c    
id :: a -> a

调用uncurry id产生类型为的函数: (b -> c, b) -> c

我们如何得到这个结果?

如何使用id(a - > a)作为第一个参数来表示,这需要一个(a - > b - > c)函数?

如果我们从制作类型的角度来看它,就会更容易理解弄清楚我们需要对id的类型做些什么才能使它适合uncurry所需的形状。 既然我们有:

id :: a -> a

我们还有:

id :: (b -> c) -> (b -> c)

这可以通过替换可以看出b -> ca在原始类型的id ,就像你可以替代Int搞清楚的类型时,而不是id 42 然后我们可以将括号放在右侧,因为(->)是右关联的:

id :: (b -> c) -> b -> c

表明id的类型适合形式a -> b -> c ,其中ab -> c 换句话说,我们可以通过专门化它已经拥有的一般类型来重塑id的类型以适应所需的形式。

理解这一点的另一种方法是看到uncurry ($)也有类型(b -> c, b) -> c 比较id($)的定义:

id :: a -> a
id a = a

($) :: (a -> b) -> a -> b
($) f x = f x

我们可以使后一个定义更加无点:

($) f = f

在这一点上, ($)只是对特定类型的id ,这一事实变得清晰。

如何使用id(a - > a)作为第一个参数来表示,这需要一个(a - > b - > c)函数?

实际上, uncurry需要(a -> (b -> c))函数。 您看得出来差别吗? :)

省略括号是邪恶的(有时候)。 这使得新手无法破译Haskell。 当然,在你收集了一些语言经验之后,你觉得你根本不需要它们了。

在这里,一旦我们明确地写出所有省略的括号,一切都变得清晰了:

uncurry :: (a -> (b -> c)) -> ((a,b) -> c)
id      ::  a ->    a

现在,编写uncurry id调用a1 -> a1a2 -> (b -> c)的类型统一。 这很简单, a1 ~ a2a1 ~ (b -> c) 只是机械的东西,这里没有创造性思维 所以问题中的id实际上有类型a -> a where a ~ (b -> c) ,因此uncurry id具有类型(b -> c,b) -> c ,通过简单替换a ~ (b -> c)进入(a,b) -> c 也就是说,它需要一对b -> c函数和一个b值,并且必须产生一个c值。

由于类型是最通用的(即没有任何关于它们的知识,因此没有特定的函数来调用可能以某种特殊方式执行该技巧),这里生成c值的唯一方法调用 b -> c使用b值作为参数。 当然,这就是($)作用。 所以uncurry id == uncurry ($) ,虽然id肯定不是 ($)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM