Where communities thrive

  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
Repo info
  • Jan 31 2019 22:17
    CrossEye commented #2779
  • Jan 31 2019 21:04
    ArturAralin commented #2779
  • Jan 31 2019 20:08
    CrossEye commented #2779
  • Jan 31 2019 18:56
    buzzdecafe commented #2631
  • Jan 31 2019 18:09
    ArturAralin commented #2779
  • Jan 31 2019 16:18
    CrossEye commented #2779
  • Jan 31 2019 16:10
    CrossEye commented #2631
  • Jan 31 2019 16:06
    CrossEye commented #2777
  • Jan 31 2019 14:44
    ArturAralin opened #2779
  • Jan 31 2019 07:39
    inferusvv commented #2631
  • Jan 31 2019 03:07
    sespinozj commented #2771
  • Jan 31 2019 02:33
    machad0 commented #2771
  • Jan 31 2019 02:26
    JeffreyChan commented #2777
  • Jan 30 2019 14:30
    CrossEye closed #2777
  • Jan 30 2019 12:13
    vanyadymousky updated the wiki
  • Jan 30 2019 01:42
    JeffreyChan commented #2777
  • Jan 29 2019 21:06
    vanyadymousky updated the wiki
  • Jan 29 2019 16:28
    CrossEye commented #2777
  • Jan 29 2019 15:50
    mbostock commented #2772
  • Jan 29 2019 15:48
    CrossEye commented #2772
Scott Sauyet

Thinking about #1543, I became puzzled by something, and I was wondering if anyone has any insight:

Because it's easy to work with, many of our examples of lift use add, so me might define mAdd = lift(add). Well add is a straightforward function, and it happens to be commutative, add(a, b) ≡ add(b, a). It simply seemed obvious that mAdd would also be commutative. In simple cases, it is:

mAdd(Maybe.Just(10), Maybe.Just(32)); //=> Maybe.Just(42)
mAdd(Maybe.Just(32), Maybe.Just(10)); //=> Maybe.Just(42)

But it's definitely not:

R.lift(R.add)(Either.Right(10), Either.Left('oops')); //=> Either.Left('oops')
R.lift(R.add)(Either.Left('oops'), Either.Right(10)); //=> Either.Right(10)

My question is: Is my intuition leading me astray? Or should we expect that if fn is commutative, then lift(fn) is also commutative? If so, is there something wrong with lift or one of its dependencies? Or is there something the matter with Either?

Never mind. It clearly cannot be commutative:

R.lift(R.add)(Either.Left('oops'), Either.Left('a-daisy'));

So my intuition is off.

Tobias Pflug
@Avaq "type transformer" ? Well you mean monad transformer right?
Aldwin Vlasblom
Is it only doable with Monads though?
Why not all Functors?
Wasn't certain about that either, so I said "type" to stay generic. :)
Aldwin Vlasblom
But now, knowing that it's just for Monads, I find more info on the internet :)
Still not sure where I'd use them though. :\
Tobias Pflug
I can prolly give you some links later
For use with JS? I would not care
For Haskell: certainly
Aldwin Vlasblom
Haha, I see. I only just started with FP a few months ago in JS, so I wouldn't know. :)
Tobias Pflug
If you want to do IO but also be able to- say encode errors with Either or Maybe you want to reach for a transformer so you can stack those monads
Haskell tho
Aldwin Vlasblom
Cool, thanks @gilligan, I'm sure I'll find my way around the Haskell examples.
Hardy Jones
@CrossEye Assuming lift doesn't do any kind of reflection or something, that Either you're using looks broken.
@CrossEye that is to say, it only uses ap, map and friends.
@Avaq it's only necessary with Monads, well more accurately it's only necessary with Chains. Really they should be called Chain Transformers, or Bind Transformers, or whatever the language uses.
but since not all languages/libraries distinguish between Monad and Chain/Bind, they have the name they have.
@Avaq the reason they are necessary is that the composition of two Chains is not necessarily another Chain.
If you take any two Functors, and compose them, the result is always a Functor.
same with Applys, and Applicatives.
Hardy Jones
What this means is that you could create a Composition data type that encoded this logic. Give it two composable data types, and you get Functor, Apply, Applicative behavior for free.
Tobias Pflug
Functor Composition would be a natural Transformation - right?
@joneshf actually- which langs /do/ differentiate between Monad/Chain ? Fantasyspec was the first time I saw that distinction
Hardy Jones
// We can compose any two `Functor`s `x` and `y`
const Comp = x => ({
  map: f => x.map(y => y.map(f)),
  toString: () => x.map(y => y.toString()).toString(),

const None = {
  map: _ => None,
  toString: () => 'None',

const Some = x => ({
  map: f => Some(f(x)),
  toString: () => `Some(${x})`,

const Left = x => ({
  map: _ => Left(x),
  toString: () => `Left(${x})`,

const Right = x => ({
  map: f => Right(f(x)),
  toString: () => `Right(${x})`,

const someRight = Comp(Some(Right(3)));
console.log(`${someRight.map(x => x + 1)}`); //=> Some(Right(4))

const someLeft = Comp(Some(Left(3)));
console.log(`${someLeft.map(x => x + 1)}`); //=> Some(Left(3))

const noneRight = Comp(None);
console.log(`${noneRight.map(x => x + 1)}`); //=> None
quick example.
so you only have to map once, rather than going down in there multiple times.
And if you have 3, 4, 5, etc types you're composing, well, you just keep on Composing.
and still you only map once.
It extends to ap and of as well.
But chain doesn't work.
so you need an explicit way to chain two data types.
Actually, I'm not sure if all data types can have a transformer version.
Hardy Jones
@gilligan purescript, scalaz, there are libs in hackage as well.
well, languages and libraries.
fantasy-land as you pointed out.
Extending the example above:

const Id = x => ({
  map: f => Id(f(x)),
  toString: () => `Id(${x})`,

const nested = Comp(Some(Comp(Id(Comp(Right(Comp(Some(Some(3)))))))));
console.log(`${nested.map(x => x + 1)}`); //=> Some(Id(Right(Some(Some(4)))))
Of course, you probably want to toString to tell you it's a Comp at each level.
Hardy Jones
but it's just a quick example :)
The creation is pretty ugly right there, but since Applicatives compose, you could factor all that out similar to how ramda does compose/pipe. and just use of a whole bunch of times.
Hardy Jones
Also, bear in mind, these are not the only things that do compose, most of the fantasy-land algebras compose.
So long as their constituents compose.
also you might need to have it be a Functor or something.
like I did with toString up there.
But you can do similarly for Setoid, and have equality for free, if the two base data types are Functor and Setoid, for example.
Aldwin Vlasblom

That's awesome @joneshf, thanks for clearing a bunch of stuff up! :)
So Monad Transformers are a ways for a Chain to say: "Here's how you can compose my chain."
And that fills in the missing gap of monadic behaviours which are otherwise all composable?
And the reason you'd want to compose Monads is the same as for why you'd want to compose any other bits of code - to keep "dry"?
So it really is mainly a convenience for not having to mapmapmap over your nested containers?

I should get more accustomed with the theory behind monads, and the laws they follow. I've been learning to use them, in the API-sense, but I've yet yo fully understand them.

Hardy Jones
yeah, that's pretty much it.