从liftA2扩展理解Applicative至liftA3的技术疑问
Applicative函子与liftAn的理解及问题解析
1. 你对liftA2的理解完全正确
你的分析逻辑没问题:
- 对于
liftA2 f x y = pure f <*> x <*> y,pure f的类型是f (a -> b -> c)(Haskell中函数默认柯里化,二元函数本质是a -> (b -> c)) - 第一步
pure f <*> x:<*>的类型是f (t -> u) -> f t -> f u,这里t=a、u=b->c,应用后得到f (b -> c) - 第二步再和类型为
f b的y做<*>,最终得到f c,完全匹配liftA2的类型签名Applicative f => (a -> b -> c) -> f a -> f b -> f c。
2. liftA3的扩展逻辑
liftA3的类型签名是:
liftA3 :: Applicative f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d
它的实现逻辑是pure f <*> x <*> y <*> z,按柯里化逐步展开:
pure f生成f (a -> b -> c -> d)(三元柯里化函数,本质是a -> (b -> (c -> d)))pure f <*> x:传入第一个参数类型a,得到f (b -> c -> d)- 再
<*> y:传入第二个参数类型b,得到f (c -> d) - 最后
<*> z:传入第三个参数类型c,得到最终结果f d
整个过程就是把柯里化的n元函数,通过<*>依次从Applicative容器中取出参数应用,最终得到包裹在容器里的结果。
3. 你的lambda版liftA3报错的原因
你写的lambda表达式\x y z -> [z x]存在类型错误:
- 这里的
z x是把x作为参数传给z,Haskell会推断z是函数类型(比如Int -> a),因此整个lambda的类型是Int -> Char -> (Int -> a) -> [a] - 但
liftA3需要的函数类型是Int -> Char -> Int -> [Int](对应三个参数:第一个Int、空格Char、第二个Int),两者类型不匹配,编译器自然要求第三个参数是Parser (Int -> a),但你传入的是Parser Int,所以报错。
而你显式定义的fnn arg1 arg2 arg3 = [arg1, arg3],类型是Int -> Char -> Int -> [Int],完全符合liftA3对函数的要求,因此可以正常运行。
正确的lambda写法应该忽略中间的空格参数,写成:
intPair = liftA3 (\x _ z -> [x, z]) posUse (char ' ') posUse
这里_表示忽略该参数,lambda的类型就变成了Int -> Char -> Int -> [Int],和fnn一致,就能正常工作了。
内容的提问来源于stack exchange,提问作者gauss_is_king
相关产品推荐
相关产品推荐

