“ {\ x y z-> [x,y,z])<$>(+3)<*>(* 2)<*>(/ 2)$ 5”如何真正起作用?

时间:2019-03-07 13:43:53

标签: haskell functor

this example from Learn you a Haskell中,作者展示了如何为函数Applicative声明->r的实例

instance Applicative ((->) r) where  
    pure x = (\_ -> x)  
    f <*> g = \x -> f x (g x)  

后来,他举了一个具体的例子

ghci> (\x y z -> [x,y,z]) <$> (+3) <*> (*2) <*> (/2) $ 5  
[8.0,10.0,2.5]  

我尝试逐步解释此片段

  1. (+3) <*> (*2) <*> (/2)视为f <*> g <*> h并认为f <*> g <*> h返回了函数\x -> f x (g x (h x)),我认为(+3) <*> (*2) <*> (/2)返回了函数\x -> x+3 (x*2 (x/2))。但是我无法在ghci中使用:t (+3) <*> (*2) <*> (/2),这会引发此错误
error:
    • Occurs check: cannot construct the infinite type:
        a1 ~ a -> a1 -> b
      Expected type: (a -> a1 -> b) -> a1
        Actual type: a1 -> a1
    • In the second argument of ‘(<*>)’, namely ‘(/ 2)’
      In the expression: (+ 3) <*> (* 2) <*> (/ 2)
  1. 如果(+3) <*> (*2) <*> (/2)返回了函数\x -> x+3 (x*2 (x/2)),它如何与lambda函数\x y z -> [x,y,z]进行模式匹配? (实际上,除了真正简单的基本功能之外,我在理解lambda函数方面仍然遇到一些麻烦。)

2 个答案:

答案 0 :(得分:7)

我认为您弄错了优先顺序。表达式

(\x y z -> [x,y,z]) <$> (+3) <*> (*2) <*> (/2) $ 5  

不包含您​​提到的那个子表达式

(+3) <*> (*2) <*> (/2)

因为应该将其解析为与左侧关联,如下所示:

((((\x y z -> [x,y,z]) <$> (+3)) <*> (*2)) <*> (/2)) $ 5

在这里,我们从左边开始简化:

(\x y z -> [x,y,z]) <$> (+3)
= { def. <$> }
(\a y z -> [(+3) a,y,z])

然后,我们继续:

(\a y z -> [(+3) a,y,z]) <*> (*2)
= { def. <*> }
(\a z -> [(+3) a, (*2) a,z])

最后,

(\a z -> [(+3) a, (*2) a,z]) <*> (/2)
= { def. <*> }
(\a -> [(+3) a, (*2) a, (/2) a])

最后一步,我们将a设为5,得到[5+3, 5*2, 5/2]

答案 1 :(得分:4)

该表达式实际上被括在左侧:

(\x y z -> [x,y,z]) <$> (+3) <*> (*2) <*> (/2) $ 5 
=
((((\x y z -> [x,y,z]) <$> (+3)) <*> (*2)) <*> (/2)) 5 
=
((((\x y z -> [x,y,z])  .  (+3)) <*> (*2)) <*> (/2)) 5 
=
 (((\x y z -> [x,y,z])  .  (+3)) <*> (*2)) 5   ((/2) 5)
=
  ((\x y z -> [x,y,z])  .  (+3)) 5   ((*2) 5)   ((/2) 5)
=
   (\x y z -> [x,y,z])    ((+3) 5)   ((*2) 5)   ((/2) 5)
=
   (\x y z -> [x,y,z])    (5+3)      (5*2)      (5/2)

=
   let x = (5+3) in (\y z -> [x,y,z])   (5*2)      (5/2)
=
   let x = (5+3) ; y = (5*2)  in  (\z -> [x,y,z])   (5/2)
=
   let x = (5+3) ; y = (5*2) ; z = (5/2)  in   [x,y,z]