hey all, is there a R.forEach for Objects? similar to what you'd expect underscore's _.each which runs a function over each element of an object?

I'm eyeing R.mapObj however that doesn't seem to do the correct behavior

ah never mind! i figured it out

instead of

`R.mapObj( entity.addComponent, components );`

I have to do :

`R.mapObj( entity.addComponent.bind( entity ), components );`

that way it will have the correct "this" when addComponent is called!@

@jethrolarson Thanks for the good read.

@mflux: that sounds a bit like abuse of

`mapObj`

, though. Are you using the return from it or simply modifying `entity`

? If it's the latter, then I would find it an odd use of `map`

.
@mflux: Probably not as efficient as hand-rolling your own, but you can build it using something like:

`var forEachObj = R.curry((fn, obj) => R.forEach(R.apply(fn), R.toPairs(obj)));`

which can be used like:

`forEachObj((k,v) => console.log(k, v), { a: 1, b: 2 });`

@scott-christopher: Very nice!

I find

`R.apply`

and `R.toPairs`

tend to go quite nicely together for a number of different scenarios.
@paldepind: Not silly at all. Quite interesting. But useful mostly for a set of types that will not be added to, since every dispatched function would have to be updated.

That is, even if you had something like

`Type.add(Shape, {Triangle: [Point, Point, Point]})`

, you have no (clean) way of updating `area`

.
@scott-christopher looks good, though I wonder why R doesn't just have a forEachObj

out of habit I started using underscore mixed with ramda and boy is that confusing to read...

it turns out I can just use R.values( obj ) and R.forEach that

Yeah, though you won’t get the keys provided to your iterator function.

If you don’t need them, then it’s probably clearer.

@CrossEye I'm glad it's not that silly. When I did it at first it felt a bit ridiculous to implement a form of types in a library. I'm not sure I completely understand. Is the issue that it's not possible to add a new type and define it's

`area`

function without modifying the existing `area`

function?
it's the expression problem

you're forced to tackle the other dimension of it when you use adt's

rather than the normal dimension in regular js

but since it's solved, you can implement a solution for it, and no harm no foul.

the obvious solution using adt's as such, is to use final interpreters

there's plenty of research and paper and tutorials on that, but the punchline is to use multiple dispatch.

```
Shape.prototype.area = function() {
return Type.case({...}, this);
};
var area = function(x) {
return x.area();
};
```

or something...

at least, the punchline in js

see also object algebras

also, I guess I didn't really explain the expression problem.

When you have an algebraic data type like that, it's very easy to add another function that operates on that type (since nothing has to be updated, only added), but very hard to add another type (since everything has to be updated as you identified and @CrossEye pointed out).

Whereas when you use inheritance (prototypal or otherwise), it's very easy to add another type (since nothing has to be updated, only added), but very hard to add another function that operates on that type (since everything has to be updated).

@joneshf Thanks for the explanation! :) I can definitely see the inflexibility there. But don't you have the same problem in Haskell if you define a algebraic data type like this:

`data Shape = Circle Float Float Float | Rectangle Float Float Float Float`

yep, and the solution is still final interpreters:

```
class Area a where
area :: a -> Double
instance Area Shape where
area (Circle r x y) = ...
area (Rectangle x y z w) = ...
```

And then if you need another type with `area`

, you just add that.

```
data Triangle = Triangle Point Point Point
instance Area Triangle where
area (Triangle a b c) = ...
```

though to really make it extensible, you'd separate out each case in the

Something to construct a thing, other things to operate on it, etc.

`Shape`

. and give more functions in the `Area`

class.Something to construct a thing, other things to operate on it, etc.

Basically make a DSL for working with shapes.

Shouldn't

`Triangle`

somehow be a part of the `Area Shape`

instance?
You have both

`data Shape = Circle Float Float Float | Rectangle Float Float Float Float`

and `data Triangle = Triangle Point Point Point`

. So `Triangle`

hasn't really extended the `Shape`

type?
hmm, docs update broke alfred-ramda-workflow,

`ramdajs.com/docs/#invoker`

format no longer works because version is always needed. I can fix this by adding version number to ramda-json-docs format, but should the latest always be available without version number? @buzzdecafe
Sorry. It was late, I didn't really explain well. Though it's kind of a poor example to explain the idea on, since there's only one operation in the language so far. But the idea is that instead of viewing `Shape`

as the type you're trying to extend, you look at the operations that you use on the data and that becomes your `type`

to extend. This makes for a DSL you can express (in the haskell case as a type class, in the js case you can stick things on the prototype). Then you program only with this DSL:

```
doubleArea :: Area a => a -> Double
doubleArea x = 2 * area x
sumAreas :: Area a => [a] -> Double
sumAreas xs = sum $ map area xs
smallest :: Area a => [a] -> a
smallest xs = minimumBy (comparing area) xs
```

This way, you don't have to rewrite anything when you add another type to `Area`

. Yet, you still retain the ability to add more functions generically--by adding another type class, or sticking more things on the prototype.

So if you wanted to add some linear transformation functions:

```
class Scale a where
scale :: Double -> a -> a
instance Scale Shape where
scale s (Circle r x y) = ...
scale s (Rectangle x y z w) = ...
instance Scale Triangle where
scale s (Triangle a b c) = ...
class Rotate a where
rotate :: Radian -> a -> a
instance Rotate Shape where
...
instance Rotate Triangle where
...
```

Once again, nothing has been modified that was already written. Only new stuff added, and all the old code still works.

And you can add even more functions without having to modify old stuff.

```
minimumArea :: (Area a, Scale a) => Double -> a -> a
minimumArea a x = if area x < a then {- some sort of computation involving `scale` -} else x
```

Does that make more sense?

translated to js that'd be like:

```
function doubleArea(x) {
return 2 * x.area();
}
function sumAreas(xs) {
return R.sum(R.map(R.invoke('area'), xs));
}
function smallest(xs) {
return R.minBy(R.invoke('area'), xs);
}
function minimumArea(size, x) {
return x.area() < size ? /* some sort of computation involving `scale` */ : x;
}
```

@joneshf Yes. It's a great explanation. I've found out that what I've implemented in silly-type is union types. I understand type classes and how different instances can implement the functions that the class specify. But in your last examples you still have

`Shape`

and `Triangle`

as two different types when `Triangle`

really should have been a value of `Shape`

? I still don't see a way to add a new value to a type once defined like this:`data Shape = Circle Float Float Float | Rectangle Float Float Float Float`

That's right, you can't

:(

why sad?

you don't lose any expressive power

you just have to pivot your viewpoint :)

But then I can't define a type

`Shape`

and extend it afterwards. That's what @CrossEye mentioned initially: "That is, even if you had something like `Type.add(Shape, {Triangle: [Point, Point, Point]})`

, you have no (clean) way of updating area."
right, because

`area`

as it was originally defined was an initial interpreter.
and there's no easy way to extend adt's and initial interpreters without rewriting something.

The initial part sort of means you've already decided on a data type to work with. Whereas the final part sort of means that you're waiting on the data type to be given to decide how to work with it.

in a hand-wavy sense.

Like

`R.map`

is a final interpreter because it seems to have the type: `Functor f => (a -> b) -> f a -> f b`

, whereas `R.of`

is an initial interpreter because it has the type: `a -> [a]`

.
you can't make `R.of`

work with other data types without rewriting the implementation (because it's an initial interpreter), but I can write:

```
function Id(x) {
this.x = x;
}
Id.prototype.map = function(f) {
return new Id(f(this.x));
}
```

And use it with `R.map`

without changing anything in the implementation (because it's a final interpreter).

```
var i3 = new Id(3);
R.map(R.inc, i3); //=> Id(4);
```

So the "type" i'm working with is the DSL for

`Functor`

. I can add more actual types (Identity, Maybe, List, etc) to this DSL, and never update the old code. But I can also add more functions to this "type" (the DSL for `Functor`

) (void, replace, etc) and also never update the old code.
it's true you cannot modify an old ADT after the fact without also modifying all the initial interpreter style functions you also wrote (this is the bulk of the expression problem). But you also don't need to if you think about the problem from a different angle.

if it sounds like a lot of trouble, that's because the problem was hard to solve :)

using either adts as the primitives or using objects as the primitives

So an initial interpreter is one that works on a type? And a final interpreter works on a type class?

pretty much

i hand-waved a bit there, but basically.

and of course, these aren't the only solutions to the problem

the point is that you haven't lost (or gained unfortunately) any expressive power, just a different view on the same stuff. And since it's a good library, you should keep going with it!

i know that if you put it on npm i'd use it for stuff

It's on npm now as

`union-type-js`

.
I've just added support for using the constructors for the native types in type specifications:

`var Action = Type({Shout: [Number, String]});`

I'll have to think a bit more about type classes :)

Sorry, i didn't mean to suggest that you NEEDED to add anything to it, just that you haven't lost anything if you really wanted to go find it again.

also, thanks!

This is very exciting. I can think of several places where this would have come on handy. I can't wait to try it.

@joneshf I didn't understand it that way :) I'm glad you shared you opinion and took the time to explain!

@CrossEye :) :D

@joneshf thanks for the lesson. what should i be reading to gain better understanding of this stuff?