9

I'm trying to get familiar with functional programming in JavaScript. I've just read that pointer functor is:

An object with an of function that puts any single value into it.

ES2015 adds Array.of making arrays a pointed functor.

And my question is what does exactly mean "single value"?

I want to make a Functor/Container (like in https://drboolean.gitbooks.io/mostly-adequate-guide/content/ch8.html) that holds grid of given dimension (width, height) as 1-dimensional array and allows me to do transformations on it. As a plain object I would store it as { width: 2, height: 2, list: [1, 2, 3, 4] } but I want to put it in a functor and I'm not sure how to do properly.

I know that it's perfectly fine to use pointed functor like this to store single value:

Container.of(47)

But is it ok to use object as value assuming object is a "single value":

Grid.of({ width: 2, height: 2, list: [1, 2, 3, 4] })

Or even like this:

Grid.of(2, 2, [1, 2, 3, 4])
jesper
  • 879
  • 8
  • 21
  • what is `Foo.of` ? did you mean Array.of? I thought, as of Es2015, only Array and *TypedArray* had `of` – Jaromanda X Aug 27 '16 at 10:11
  • And what is your expected output? Didn't quite get your point. – Leo Aug 27 '16 at 10:15
  • Please give an example of your input data, and expected resulting array content - as it stands, you've confused me with `Foo` – Jaromanda X Aug 27 '16 at 10:17
  • 1
    In ES5 `Array.of` is pointed function because, unlike `Array`, it interprets passed arguments in a single way no metter what arguments and how many arguments you pass, while `Array` differently interprets `Array(5)` and `Array(5, 7)`. If you want to make your `Foo.of` a pointed function, force it to interpret arguments in a single way no matter what you pass to it. –  Aug 27 '16 at 10:23
  • Maybe you are looking for an approach to [flatten multi-dimensional array](http://stackoverflow.com/a/27267762/1032492)? – Leo Aug 27 '16 at 10:28
  • I rephrase the question. `Array.of` is just an example stated in definition. It's not a about array at all. I hope it's clear now. – jesper Aug 27 '16 at 10:33
  • Actually `of` is part of the applicative functor class. Using `of` along with `ap` is equivalent with just using `map`. `of` is required for applicatives in order to proof the applicative laws. Consequently it isn't particular useful in connection with functors. Just use the normal constructor to create functors. –  Nov 18 '16 at 18:39
  • @ftor `of` Why isn't it useful? It can be used without the need to define `ap` (in case you don't need it, which can happen). – Dmitri Zaitsev Jan 23 '17 at 21:04

2 Answers2

9

The explanation in https://github.com/hemanth/functional-programming-jargon is unfortunately not very accurate.

A pointed functor is really a functor F together with a function of defined for every type a, and sending a value x of type a into a value of(x) of type F a. In Hindley-Milner signature it looks like this:

of :: a -> F a

For instance, the Array functor is pointed with of = x => [x], defined for every value x of any type a.

Further, the function of (or more precisely, the collection of functions of as you have one for each type a) must be a natural transformation from the identity functor into F. Which means that of applied to a function's value equals of applied to the function's argument and then mapped over the function:

of(f(x)) === of(x).map(f)

For instance, in the Array example you have

[f(x)] === [x].map(f),

so x => [x] is indeed a natural transformation.

But you can also redefine of as

of = x => [x, x]
[f(x), f(x)] === [x, x].map(f)

which makes Array into another pointed functor, even if the map method remains the same. (Note that in each case, you only get very special arrays as values of of(x).)

However, you cannot define your of as e.g.

of = x => [x, 0]
[f(x), 0] !== [x, 0].map(f)

Now

var grid = Grid.of({ width: 2, height: 2, list: [1, 2, 3, 4] })

is perfectly ok and returns your object passed wrapped into Grid. Then you can map your grid with any regular function f from plain objects into plain objects and the result will be the same as applying f and wrapping into Grid, because of the natural transformation law. Note that this way you can also call Grid.of with any other value like Grid.of({width: 2}) of even Grid.of(2). Alternatively, you can restrict the types for which Grid.of is defined, then the value must only be of a type that you allow.


This one is a bit tricky:

Grid.of(2, 2, [1, 2, 3, 4])

This applies Grid.of to several arguments. Since Grid.of is by definition a function of only one argument, the result will be Grid.of(2), which may not be what you want. If you really want to feed all values, you probably want to write

Grid.of([2, 2, [1, 2, 3, 4]])

Alternatively, you can extend Grid.of to multiple arguments by pre-wrapping them into an array internally and then applying Grid.of. It really depends on what you are after.

For a real world usage example, see e.g. here where a "boring" Task is defined via Task.of from a plain value. On the other hand here is a more interesting Task wrapping a function that you wouldn't get with Task.of. What is important though, is that both Tasks can be used with the same uniform interface as shown on both examples.

Also note that no applicative functors are used in these examples, so there are still uses of pointed functors without being applicative.


ADDED.

See also https://github.com/MostlyAdequate/mostly-adequate-guide-it/blob/master/ch9.md#pointy-functor-factory for a nice introduction and real world uses of the Pointed Functor.

Dmitri Zaitsev
  • 13,548
  • 11
  • 76
  • 110
3

But is it ok to use object as value assuming object is a "single value":

Yes. of is supposed to take any value and put it inside the container. An object certainly is such a single value.

Grid.of(2, 2, [1, 2, 3, 4])

No. of is supposed to take a single parameter. If you want to put multiple values inside a functor, put them inside an other structure before and put that structure inside the functor, or construct the functor by something else than its point function (of).

Grid.of({ width: 2, height: 2, list: [1, 2, 3, 4] })

No, if you expect that to return the input then it won't work. of should take the input as-is and wrap the structure around it. In case of your grid, it would most certainly look like this:

// Grid<A>
class Grid {
    // Int -> Int -> [A] -> Grid<A>
    constructor(w, h, vals) {
        assert(Number.isInteger(w) && Number.isInteger(h));
        this.width = w;
        this.height = h;
        const list = Array.from(vals);
        assert(list.length == w * h);
        this.list = list;
    }
    // Grid<A> -> (A -> B) -> Grid<B>
    map(f) {
        return new Grid(this.width, this.height, this.list.map(f));
    }
    // A -> Grid<A>
    static of(x) {
        return new Grid(1, 1, [x]);
    }
}

So the above call would create a Grid of objects, not a grid of four numbers. Notice that of is not the only way to construct an instance of a functor, it's only the way to construct an instance from a single element.

Notice that of is most important as part of an Applicative, not so much interesting for ordinary Functors. Btw, if you're interested in functional programming concepts, you should also be able to make your Grid a Monoid, a Traversable and a Monad - see https://github.com/fantasyland/fantasy-land.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • So it seems I don't need `of` at all and all I need is a decent way of creating an object. I was avoiding classes as they seem to be non-functional to me and I never saw them in any kind of tutorials... Now I see these two world can be combine into one. – jesper Aug 27 '16 at 14:20
  • How to make a constructor pure? I image that `assert` should throw some kind of exception in OOP world but what if I wanted to make it purely functional? I'm kind of familiar with Either, Left and Right but I'm not sure how to apply it here. One solution I have is to delegate creating of Grid object to a function which checks if provided values specifies a valid grid and then returns _either_ a Grid object or error. Is this a right approach? – jesper Aug 27 '16 at 14:36
  • 1
    @jesper: Yes, `of` is not required and not meant to be the only way for creating instances. You only need it if you want your data type conform to the fantasy-land specification, which makes it work out of the box with many functional libraries such as Ramda. And yes, `class`es are by no means conflicting with a functional approach - you always need some way to do "records" or "objects" to hold data. You can do the same with a factory function and static functions, I've just chosen the `class` syntax here as it is shorter. – Bergi Aug 27 '16 at 15:15
  • 1
    @jesper: The constructor should always be pure indeed. Throwing exceptions is fine when you expect it to be called only with valid inputs in your program. The type safety (int, iterable, etc) could be ensured by a compiler or be expected by documentation. If you want to be sure, you would let your users only construct valid instances by making the constructor private (uh, it's easier in Haskell than in JS) and export only a function that does the validation itself (or e.g. takes only the width and computes the height from the length of the input list). – Bergi Aug 27 '16 at 15:21