LiftItOut Functor实例中fmap调用失败的问题咨询
问题分析与解决
1. 直接错误:(\x -> 3 x)的类型不合法
Haskell里函数应用是左结合的,3 x相当于把数值3当作函数去调用参数x,但3是Num类型的值,不是函数,这直接触发类型错误——你不能用数值去“调用”另一个值。你想要的是把3传入(+3)得到结果,但这不是fmap的作用场景。
2. 搞懂(-> r) Functor的fmap逻辑
函数类型r -> a(也就是(->) r a)的Functor实例,fmap的作用是函数复合,定义如下:
instance Functor ((->) r) where fmap f g = f . g -- 等价于 \x -> f (g x)
简单说,fmap在这里是把两个函数“串”起来:先执行g,再把结果传给f。比如fmap (+1) (*2)会得到一个新函数\x -> x*2 + 1,而不是给(*2)传参。
3. 实现你的预期效果
如果你想得到LiftItOut 6(把3传入(+3)后的结果包装),不需要用fmap,直接调用函数再包装即可:
LiftItOut $ (+3) 3
如果一定要用fmap来实现类似“给函数传参”的效果,你需要构造一个能接收函数并传参的函数,再用fmap复合:
-- 定义一个函数:接收函数f,返回f 3的结果 let apply3 f = f 3 -- 用fmap把apply3和(+3)复合,得到LiftItOut (\x -> apply3 ((+3) x)) -- 不过这是先给(+3)传x,再把结果传给apply3,和你预期的直接传3不一样,直接调用更直接
再举个fmap在函数Functor上的正确例子
比如我们有一个乘2的函数包装在LiftItOut里,想用fmap给结果加1:
let liftedDouble = LiftItOut (*2) let liftedDoublePlus1 = fmap (+1) liftedDouble -- 此时liftedDoublePlus1是LiftItOut (\x -> x*2 +1) -- 要得到具体值,需要取出函数调用: case liftedDoublePlus1 of LiftItOut f -> f 3 -- 得到9
内容的提问来源于stack exchange,提问作者Dudu Dudu
相关产品推荐
相关产品推荐

