"(\x y z -> [x,y,z]) <$> (+3) <*> (*2) <*> (/2) $ 5 " 是如何工作的?

How does "(\x y z -> [x,y,z]) <$> (+3) <*> (*2) <*> (/2) $ 5 " really work?

this example from Learn you a Haskell中,作者展示了如何为函数->r

声明一个Applicative的实例
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 return 是一个函数 \x -> f x (g x (h x)),我认为 (+3) <*> (*2) <*> (/2) return是一个函数 \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) 执行 return 函数 \x -> x+3 (x*2 (x/2)),它如何与 lambda 函数进行模式匹配 \x y z -> [x,y,z]? (实际上,除了最基本的简单函数之外,我在理解 lambda 函数方面仍然遇到一些困难。)

那个表达式实际上是在左边用括号括起来的:

(\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]    

我想你搞错了优先顺序。表达式

(\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].