[Functional Programming] Working with two functors(Applicative Functors)-- Part2 --liftAN
Let's examine a pointfree way to write these applicative calls. Since we know map
is equal to of/ap
, we can write generic functions that will ap
as many times as we specify:
const liftA2 = curry((g, f1, f2) => f1.map(g).ap(f2)); const liftA3 = curry((g, f1, f2, f3) => f1.map(g).ap(f2).ap(f3)); // liftA4, etc
Let's see the previous examples written this way:
const profile = name => email => `${name}__${email}`; const safeProfile = liftA2(profile); const res1 = safeProfile(prop('name', user), prop('email', user)); // John Doe__blurp_blurp
liftA2(add, Maybe.of(2), Maybe.of(3)); // Maybe(5) liftA2(renderPage, Http.get('/destinations'), Http.get('/events')); // Task('<div>some page with dest and events</div>') liftA3(signIn, getVal('#email'), getVal('#password'), IO.of(false)); // IO({ id: 3, email: 'gg@allin.com' })
liftAN: Lift a curry function into a Functor context, which will be define later;
liftA2(add, Maybe.of(2), Maybe.of(3)); Maybe will be the Functor context for 'add' function which has been lifted
Laws:
Identity
// identity A.of(id).ap(v) === v;
For example:
const v = Identity.of('Pillow Pets'); Identity.of(id).ap(v) === v;
Homomorphism
// homomorphism A.of(f).ap(A.of(x)) === A.of(f(x));
A homomorphism is just a structure preserving map. In fact, a functor is just a homomorphism between categories as it preserves the original category's structure under the mapping.
A quick example:
Either.of(toUpperCase).ap(Either.of('oreos')) === Either.of(toUpperCase('oreos'));
Interchange
The interchange law states that it doesn't matter if we choose to lift our function into the left or right side of ap
.
// interchange v.ap(A.of(x)) === A.of(f => f(x)).ap(v);
Here is an example:
const v = Task.of(reverse); const x = 'Sparklehorse'; v.ap(Task.of(x)) === Task.of(f => f(x)).ap(v);
Composition
// composition A.of(compose).ap(u).ap(v).ap(w) === u.ap(v.ap(w));
const u = IO.of(toUpperCase); const v = IO.of(concat('& beyond')); const w = IO.of('blood bath '); IO.of(compose).ap(u).ap(v).ap(w) === u.ap(v.ap(w));
Examples:
const safeAdd = curry((a, b) => Maybe.of(add).ap(a).ap(b)); const safeAdd = liftA2(add); const localStorage = { player1: { id:1, name: 'Albert' }, player2: { id:2, name: 'Theresa' }, }; // getFromCache :: String -> IO User const getFromCache = x => new IO(() => localStorage[x]); // game :: User -> User -> String const game = curry((p1, p2) => `${p1.name} vs ${p2.name}`); // startGame :: IO String const startGame = liftA2(game, getFromCache('player1'), getFromCache('player2'));
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2018-02-27 [CSS3] Create Dynamic Styles with CSS Variables
2017-02-27 [Flow] The Fundamentals of Flow
2017-02-27 [Angular] Some performance tips
2017-02-27 [Ramda] Rewrite if..else with Ramda ifElse
2016-02-27 [Hapi.js] Up and running