1

I'm now reading "mostly adequate guide to functional programming" by Professor Frisby, and I was wondering how can we do pure fetching, and I saw this piece of code here in the book

const pureHttpCall = memoize((url, params) => () => $.getJSON(url, params));

And says

The interesting thing here is that we don't actually make the http call - we instead return a function that will do so when called. This function is pure because it will always return the same output given the same input: the function that will make the particular http call given the url and params.

where that left me with some confusion, I don't understand how pureHttpCall is now pure and still have impure underlying code (the fetching part).

So what am I missing here that makes the code pure and functional?

2 Answers2

2

What makes the function pure is this:

memoize( ... )

Memoizing is a special kind of caching. You may be familiar with caching. That is, you store the result of an expensive operation in a variable and if that variable already exist return the value of that variable instead of performing the expensive operation. Memoizing is exactly that.

The main difference between memoizing and caching is that memoizing is a permanent cache - most commonly used caching algorithm has an invalidation process: it could be time based (delete the cache if it is older than x), count based (delete the cache if there are more than x items cached), memory based (delete the cache if the cache uses more than x megabytes of RAM) etc. Memoizing never deletes the cache. Therefore the expensive operation is done only once.

The fact that an operation is done only once causes every call to pureHttpCall to be guaranteed to return the same result. This means that the function is now pure.

Yes you can do the same to Math.random() if you memoize it making every call to pureRandom return exactly the same number. And this would make pureRandom pure because it always returns the same result. I personally would not call it a "random" function.

A very simple implementation of memoize could be something like this:

function memoize (fn) {
    let cache;
    return function () {
        if (cache === undefined) {
            cache = fn();
        }

        return cache;
    }
}

The above code is 100% synchronous for clarity but it is possible to write an asynchronous version of a memoization function.

slebetman
  • 109,858
  • 19
  • 140
  • 171
  • Thanks for taking time to answer! In some sense the `fetch` is also now useless because of memoizing. + if we change the url or the param, the memoizer will not find it in the cache, so it will make a new call, so is it not pure now? – Ahmad M. Hawwash Mar 09 '22 at 07:59
  • You can write a memoizing function that stores the results in an object (eg. `cache[url+','+JSON.stringify(params)] = result`) so you can get different results if you call it with different arguments. As long as the same arguments always return the same result then the function is pure – slebetman Mar 10 '22 at 01:40
  • 1
    `pureHttpCall` is not pure because of the memoization. It's pure because of the thunk, i.e. `() =>` which returns a description of the http call instead of actually performing the http call. See, https://stackoverflow.com/a/57711370/783743. – Aadit M Shah Mar 19 '22 at 03:23
0

As I understand it, the author is arguing here that because the caching layer is added, the function now has predictable results:

Once you have done a combination of the input arguments, that same combination will always return the same result it produced the first time.

So if you unplug your ethernet cable and do pureHttpCall("http://google.com") you will get an error response back. If you now replug your cable, then pureHttpCall("http://google.com") will still produce that exact same error you got the first time.

I don't think I agree though, because the there is an implicit dependency here. The function still depends on the environment when it is first called. E.g. If you restart your program between unpluggin and replugging your ethernet cable, you will get different results.

Tom Moers
  • 1,243
  • 8
  • 13
  • 1
    No, that's incorrect. The author is arguing that the function is pure because you're not performing an http call at all. Instead, you're returning a thunk which when called performs the http call. This thunk is a description of an IO action. Hence, it's pure. See, https://stackoverflow.com/a/57711370/783743. – Aadit M Shah Mar 19 '22 at 03:25
  • I agree, creating the thunk is indeed pure (in this case, doing the memoize call). But then the writing gets ambiguous for me. I quote: "[snip] we don't actually make the http call - we instead return a function that will do so when called. This function is pure [snip]". The 'this function' (i think) refers to the thunk itself. Which is not pure, except if you agree with the argument I explained in my answer – Tom Moers Mar 20 '22 at 15:54
  • In the above quote, “this function” refers to `pureHttpCall`. However, I agree that the author's wording is unclear. – Aadit M Shah Mar 21 '22 at 04:18
  • Indeed, and pureHttpCall is the thing doing the http call (in a memoized fashion). Creating pureHttpCall is pure. And in the traditional sense calling it isn't, but the author seems to argue otherwise. – Tom Moers Mar 22 '22 at 06:11