2012-01-20 60 views
16

考虑:为什么要编译Haskell代码?

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

调用uncurry id结果类型的函数:(b -> c, b) -> c

我们如何得到这样的结果?

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

回答

25

它很容易理解,如果我们尝试看看它的使得工种出点:搞清楚什么,我们需要做的id的类型得到它,以适应由uncurry所需的形状。既然我们有:

id :: a -> a 

我们也有:

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

这可以通过在原有类型的idab -> c可以看出,正如搞清楚类型时,可能会替代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一个专业化更具体类型变得清晰。

+2

谢谢!这开始有意义!我仍然觉得它有点出风头! – ssanj

+1

@ssanj:如果有任何安慰,把它写成'uncurry id'而不是'uncurry($)'是邪恶的:) – ehird

+1

如果你想特别邪恶,你可以写'(\'id \'3) '而不是'($ 3)'或者将'id'定义为'infixr 0'''''并且用它来代替'($)',比如'(^ 2)''''1 + 2 * 3'。 – Vitus

8

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

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

省略括号是邪恶的(好,有时)。这使得新手无法破译Haskell。当然,在你学习了这门语言的一些经验之后,你觉得你已经不再需要他们了。

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

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

现在,写的a1 -> a1a2 -> (b -> c)一种统一uncurry id电话。这很简单,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肯定是不是($)

+0

'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'。 –