[Functional Programming] Async IO Functor

We will see a peculiar example of a pure function. This function contained a side-effect, but we dubbed it pure by wrapping its action in another function. Here's another example of this:

// getFromStorage :: String -> (_ -> String)
const getFromStorage = key => () => localStorage[key];

'localStorage' is a side effect, but we wrap into a function call, so what 'getFromStorage' return is not a value but a function. And this returned function is waiting to be called, before calling, we can do all kind of function mapping of composion on it, that's the beautity.

 

Let's see how to define a IO functor for this side-effect code:

复制代码
class IO {
  static of(x) {
    return new IO(() => x);
  }

  constructor(fn) {
    this.$value = fn;
  }

  map(fn) {
    return new IO(compose(fn, this.$value));
  }

  inspect() {
    return `IO(${this.$value})`;
  }
}
复制代码

IO will take a function as input. 

 

Example of IO:

( Note: the reuslt shown in comment is not actual result, the actual result is wrapped in {$value: [Function]}, just for now, we show the result which should be in the end.)

复制代码
// ioWindow :: IO Window
const ioWindow = new IO(() => window);

ioWindow.map(win => win.innerWidth);
// IO(1430)

ioWindow
  .map(prop('location'))
  .map(prop('href'))
  .map(split('/'));
// IO(['http:', '', 'localhost:8000', 'blog', 'posts'])
复制代码

 

There is some library already define the IO functor for us, we don't need to write one for our own, for example, Async from Crocks.js, or Data.Task from Folktale.

Here we are using 'Data.Task' as an example:

复制代码
// -- Node readFile example ------------------------------------------

const fs = require('fs');

// readFile :: String -> Task Error String
const readFile = filename => new Task((reject, result) => {
  fs.readFile(filename, (err, data) => (err ? reject(err) : result(data)));
});

readFile('metamorphosis').map(split('\n')).map(head);
// Task('One morning, as Gregor Samsa was waking up from anxious dreams, he discovered that
// in bed he had been changed into a monstrous verminous bug.')


// -- jQuery getJSON example -----------------------------------------

// getJSON :: String -> {} -> Task Error JSON
const getJSON = curry((url, params) => new Task((reject, result) => {
  $.getJSON(url, params, result).fail(reject);
}));

getJSON('/video', { id: 10 }).map(prop('title'));
// Task('Family Matters ep 15')


// -- Default Minimal Context ----------------------------------------

// We can put normal, non futuristic values inside as well
Task.of(3).map(three => three + 1);
// Task(4)
复制代码

 

To run the Task, we need to call 'fork(rej, res)':

复制代码
// -- Pure application -------------------------------------------------
// blogPage :: Posts -> HTML
const blogPage = Handlebars.compile(blogTemplate);

// renderPage :: Posts -> HTML
const renderPage = compose(blogPage, sortBy(prop('date')));

// blog :: Params -> Task Error HTML
const blog = compose(map(renderPage), getJSON('/posts'));


// -- Impure calling code ----------------------------------------------
blog({}).fork(
  error => $('#error').html(error.message),
  page => $('#main').html(page),
);
复制代码

 

Example of Either & IO:

复制代码
// validateUser :: (User -> Either String ()) -> User -> Either String User
const validateUser = curry((validate, user) => validate(user).map(_ => user));

// save :: User -> IO User
const save = user => new IO(() => ({ ...user, saved: true }));

const validateName = ({ name }) => (name.length > 3
  ? Either.of(null)
  : left('Your name need to be > 3')
);

const saveAndWelcome = compose(map(showWelcome), save);

const register = compose(
  either(IO.of, saveAndWelcome),
  validateUser(validateName),
);
复制代码

 

More detail

 

posted @   Zhentiw  阅读(241)  评论(0编辑  收藏  举报
编辑推荐:
· 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工具
历史上的今天:
2017-02-23 [HTML5] Focus management using CSS, HTML, and JavaScript
2017-02-23 [TypeScript] Increase TypeScript's type safety with noImplicitAny
2017-02-23 [React] displayName for stateless component
2016-02-23 [Protractor] Locators and Suites in Protractor
点击右上角即可分享
微信分享提示