2011-03-18 61 views
12

虽然试图更好地了解应用型,我看着<定义*>,这往往被定义为AP,而这又被定义为:如何以及为什么被AP定义为liftM2 ID在Haskell

ap    :: (Monad m) => m (a -> b) -> m a -> m b 
ap    = liftM2 id 

纵观类型签名liftM2和ID,即:

liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r 
id      :: a -> a 

我不明白只是通过传递ID,类型签名的相关部分看起来如何改造从(a1 -> a2 -> r) -> m a1m (a -> b)。我在这里错过了什么?

+9

也许拼写'AP = liftM2($)'会更照明。这意味着完全一样的东西。 – luqui 2011-03-19 01:30:04

+8

@luqui:只为那些不知道的人,'($)'只是专用于功能的'id'。 – fuz 2011-03-19 10:56:00

回答

17

id的类型变量a可以实例化为任何类型,在这种情况下,该类型为a -> b

所以我们实例化id(a -> b) -> (a -> b)。现在可变a1liftM2类型被在(a -> b)实例化,a2a被实例化,并且rb中实例化。

综合起来,liftM2((a -> b) -> (a -> b)) -> m (a -> b) -> m a -> m bliftM2 id :: m (a -> b) -> m a -> m b处被实例化。

+0

我不得不通读几遍才能点击它,但它终于开始了。谢谢回答。 – 2011-03-19 12:44:36

2

最好的答案是绝对正确的,并且可以从单独的类型快速有效地工作。一旦你擅长Haskell(免责声明:我不是),那么这是理解这一点比效率函数定义更有效的方法。

但是由于我最近不得不在ap这个问题上与ap纠缠在一起,所以我决定分享我的经验,因为它可能会提供一些额外的直觉。首先,就像单体挑战问一样,我将使用名称bind来指主要Monad运算符>>=。我认为这有很大帮助。

如果我们定义我们自己的liftM2版本中,我们可以这样做:

liftM2 :: (Monad m) => (a -> b -> c) -> m a -> m b -> m c 
liftM2 f ma mb = 
    ma `bind` \a -> 
    mb `bind` \b -> 
    return $ f a b 

我们希望以此来帮助我们创建ap。假设我们为f选择了正确的函数,让我们暂时将函数f单独保留一会儿,然后考虑如何将其作为ap

假设我们要传递一个函数值Monad作为上面的第一部分,即ma部分。它可能类似于Just (+3)[(+3), (*2)] - 一些生活在Monad环境中的“功能”。

而且我们提供一个参数值单子作为第二部分,所述mb部分,如Just 5[6,7,8] - 一些“值”生活在一个单子上下文,其可以用作用于活内部ma函数的参数。

那我们会

liftM2 f (m someFunction) (m someArgument) = 
    (m someFunction) `bind` \a -> 
    (m someArgument) `bind` \b -> 
    return $ (f a b) 

和lambda函数内以下bind,我们知道asomeFunctionbsomeArgument - 而那正是bind的作用:它模拟的提取来自Monad上下文的值以对该Monad唯一的任何特殊处理为模。

所以这最后一行真的成为

return $ f someFunction someArgument 

现在,让我们退后一步,记住,我们在创造ap目标是调用someFunctionsomeArgument单子上下文里面。因此,无论我们使用return产量,它都需要是功能应用someFunction someArgument的结果。

那么怎样才能使两个表达式等于

f someFunction someArgument ==? someFunction someArgument 

好吧,如果我们让x = (someFunction someArgument)那么我们正在寻找一个功能f,从而

f x = x 

,所以我们知道, f需要是id

回到起点,这意味着我们正在寻找liftM2 id

基本上liftM2 id ma mb说我该怎么办m (id a b)所以如果a是可以在b操作功能,然后将id“只是让他们独立”,让a做的事情b,而返回的内部结果Monad上下文。

这就像我们迫使liftM2有旁观者的偏见。

而为了让这工作了,a必须有一个函数类型,从“TypeOfb”到“SomeReturnType”,或TypeOfb -> SomeReturnType去,因为ba的预期参数。当然b必须有TypeOfb

如果你允许我表示法的一个弊端,那任意让我们只用符号“A”来表示“TypeOfb”符号“B”来表示“SomeReturnType”:

`b` --> "a" is its type 
`a` --> "a -> b" is its type 

然后,对于ap类型签名将是

ap :: Monad m => m (TypeOfB -> SomeReturnType) -> m TypeOfB -> m SomeReturnType 
==> 
ap :: Monad m => m (a -> b) -> m a -> m b 
相关问题