Fantasy-land: What is it called when one of these methods gets applied to a Functor's value?

Created on 16 Jan 2017  路  8Comments  路  Source: fantasyland/fantasy-land

The simplest example I can think of is here:

https://github.com/folktale/data.either/blob/master/lib/either.js#L252-L259

An Either doesn't exactly have a concat, but if its an Either of a Semigroup, then you can concat the underlying Semigroup simply by calling concat. Is there a specific term for these kind of operations on the values of functors? They're basically just a layer of indirection on top of map or chain.

I'm building a parser combinators library and I'm not sure if its Kosher to allow a concat method to join parser results together.

  concat(p) {
    return this.chain(vs => p.map(v => vs.concat([v])))
  }
question

Most helpful comment

@ccorcos I don't have an answer to your title question. The examples you give can lead to some discussion though. Either a b has more than one implementation for Semigroup. For instance:

const Left = x => ({
  concat: other => other,
});

const Right = x => ({
  concat: _ => Right(x),
});

That implementation does not rely at all on the underlying value. I know you mentioned Either a b as an example, but it's important to remember that we can sometimes do things differently.

Your parser combinator library could function in a similar way. Instead of trying to concat the underlying value, concat the structure. This is what naturally falls out of parser combinators anyway in a language with support for higher kinded polymorphism. The Alt, Plus, and Alternative algebras follow naturally from parser combinators. The reason we have alt as f a ~> f a -> f a instead of a ~> a -> a is precisely because we want to talk about concating the structure and not the underlying value.

The point I'm trying to make is that you should explore using Alt, Plus, and Alternative for your parser combinator library.

All 8 comments

So in the item you picked is assuming that anything within the Right constructor is also a Semigroup, but I don't know of a specific term for it, other than the Either also being a Semigroup because the item with in Either also fulfills being a Semigroup.

If you're type doesn't then it won't work obviously, but again I think because javascript has no notion of types in this way, I don't think there was a term for this. I'm also waiting for "Cunningham's Law" :)

https://hackage.haskell.org/package/base-4.9.1.0/docs/Data-Semigroup.html#t:Semigroup

@ccorcos I don't have an answer to your title question. The examples you give can lead to some discussion though. Either a b has more than one implementation for Semigroup. For instance:

const Left = x => ({
  concat: other => other,
});

const Right = x => ({
  concat: _ => Right(x),
});

That implementation does not rely at all on the underlying value. I know you mentioned Either a b as an example, but it's important to remember that we can sometimes do things differently.

Your parser combinator library could function in a similar way. Instead of trying to concat the underlying value, concat the structure. This is what naturally falls out of parser combinators anyway in a language with support for higher kinded polymorphism. The Alt, Plus, and Alternative algebras follow naturally from parser combinators. The reason we have alt as f a ~> f a -> f a instead of a ~> a -> a is precisely because we want to talk about concating the structure and not the underlying value.

The point I'm trying to make is that you should explore using Alt, Plus, and Alternative for your parser combinator library.

This is what naturally falls out of parser combinators anyway in a language with support for higher kinded polymorphism

That's the key to this imo.

Thanks for the responses :) I understand there could be more semigroups for a single data type, but the example you give for Either isnt exactly useful how the other one is... It seems to me that the answer is that this shouldnt actually be allowed. You shouldn't be able to concat two Eithers in a way that assumes its value to be a Semigroup. That is unless you specifically define that the value of an Either must be a Semigroup.

The point I'm trying to make is that you should explore using Alt, Plus, and Alternative for your parser combinator library.

I spent a lot of time figuring out what everything in FantasyLand meant and why they were useful and then you guys added all these new types and I have no idea what they mean lol. I think FantasyLand would be infinitely more valuable to people if there was a section for examples of each of these types in practical situations.

Cheers,

Chet

You shouldn't be able to concat two Eithers in a way that assumes its value to be a Semigroup. That is unless you specifically define that the value of an Either must be a Semigroup.

But this is the side effect of javascript not having types and that a compiler like ghc could infer that your type with in Either is also a Semigroup, for javascript users we have to infer that with knowledge and that's hard to do long term with large/complex apps .

And why the rise of Purescript (see below) and Elm is becoming very, very attractive.

instance semigroupEither :: (Semigroup b) => Semigroup (Either a b) where
  append x y = append <$> x <*> y

the example you give for Either isnt exactly useful how the other one is...

I find it pretty useful.

const gt10 = x => x > 10 ? Right(x) : Left("too small");
[1,5,124,41,31,2,3,13].reduce((acc, x) => acc.concat(gt10(x)), Left("empty"))
//=> Right(124)
[1,5,1,2,4,4,1,3,1,2,3,1,3].reduce((acc, x) => acc.concat(gt10(x)), Left("empty"))
//=> Left("too small")
[].reduce((acc, x) => acc.concat(gt10(x)), Left("empty"))
//=> Left("empty")

I can make a safe find that tells me what happened without trying too hard. It's safe in the sense that I don't have to deal with null or undefined.

It seems to me that the answer is that this shouldnt actually be allowed. You shouldn't be able to concat two Eithers in a way that assumes its value to be a Semigroup.

That's too restrictive and not really something the spec should care about. It's way too low level of a thing to add. In the scope of Semigroup, we shouldn't care if an Either a b data type even exists. We should definitely not special case the spec for data types. That leads to the craziness of promises.

It also severely limits the usefulness of Semigroup. You'd expect that something like this could be written once and for all:

const lift2 = f => x => y => y.ap(x.map(f));
const concat = a => b => a.concat(b);
const applyConcat = lift2(concat);

But saying that Either a b cannot do such a thing would make this function really awkward.

That is unless you specifically define that the value of an Either must be a Semigroup.

data.either does that in this case: https://github.com/folktale/data.either/blob/f9b20a582c7287528df328a5d13a662b8d454b52/lib/either.js#L244. Well, it requires a Monoid, but close enough.

I think FantasyLand would be infinitely more valuable to people if there was a section for examples of each of these types in practical situations.

Please contribute with some examples! You're writing a perfect one for Alt, Plus and Alternative. There's more discussion here: https://github.com/fantasyland/fantasy-land/issues/177.

All great answers and I totally agree.

But @joneshf can't you do that with a traversal? Maybe I'm barking up the wrong tree.

Sure. Lots of different functions can be used to do similar things.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

safareli picture safareli  路  12Comments

davidchambers picture davidchambers  路  8Comments

ulfryk picture ulfryk  路  4Comments

wenkanglin picture wenkanglin  路  4Comments

Raynos picture Raynos  路  3Comments