uncurry :: (a-> b -> c) -> (a,b) -> c
id :: a -> a
调用uncurry id
结果类型的函数:(b -> c, b) -> c
我们如何得到这样的结果?
如何使用id(a - > a)作为uncurry的第一个参数,这需要(a - > b - > c)函数?
uncurry :: (a-> b -> c) -> (a,b) -> c
id :: a -> a
调用uncurry id
结果类型的函数:(b -> c, b) -> c
我们如何得到这样的结果?
如何使用id(a - > a)作为uncurry的第一个参数,这需要(a - > b - > c)函数?
它很容易理解,如果我们尝试看看它的使得工种出点:搞清楚什么,我们需要做的id
的类型得到它,以适应由uncurry
所需的形状。既然我们有:
id :: a -> a
我们也有:
id :: (b -> c) -> (b -> c)
这可以通过在原有类型的id
为a
代b -> c
可以看出,正如搞清楚类型时,可能会替代Int
代替的id 42
。然后,我们可以拖放到右侧的括号,因为(->)
是右关联:
id :: (b -> c) -> b -> c
表明id
的类型适合的形式a -> b -> c
,其中a
为b -> 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)作为uncurry的第一个参数,这需要(a - > b - > c)函数?
实际上,uncurry
要求(a -> (b -> c))
功能。您看得出来差别吗? :)
省略括号是邪恶的(好,有时)。这使得新手无法破译Haskell。当然,在你学习了这门语言的一些经验之后,你觉得你已经不再需要他们了。
在这里,一旦我们写出所有省略后面的括号明确这一切都变得清晰:
uncurry :: (a -> (b -> c)) -> ((a,b) -> c)
id :: a -> a
现在,写的a1 -> a1
有a2 -> (b -> c)
一种统一uncurry id
电话。这很简单,a1 ~ a2
和a1 ~ (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
肯定是不是($)
。
'uncurry f(x,y)= f x y; id z = z; uncurry id(x,y)= id x y = x y; uncurry id = \(x,y) - > x y; uncurry id ::(a - > b,a) - > b'。 –
谢谢!这开始有意义!我仍然觉得它有点出风头! – ssanj
@ssanj:如果有任何安慰,把它写成'uncurry id'而不是'uncurry($)'是邪恶的:) – ehird
如果你想特别邪恶,你可以写'(\'id \'3) '而不是'($ 3)'或者将'id'定义为'infixr 0'''''并且用它来代替'($)',比如'(^ 2)''''1 + 2 * 3'。 – Vitus