Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

some/many on Alternative #3454

Open
johnynek opened this issue Jun 3, 2020 · 4 comments
Open

some/many on Alternative #3454

johnynek opened this issue Jun 3, 2020 · 4 comments

Comments

@johnynek
Copy link
Contributor

johnynek commented Jun 3, 2020

Haskell's Alternative has some/many defined as:

some v = (:) <$> v <*> many v
many v = some v <|> pure []

We couldn't add those because without laziness the simple thing doesn't terminate. However, now that we have Defer[F] we can actually write these methods:

  def listOf[A](fa: F[A])(implicit F: Defer[F]): F[List[A]] =
    combineK(map(nonEmptyListOf(fa)(_.toList)), pure(Nil))

  def nonEmptyListOf[A](fa: F[A])(implicit F: Defer[F]): F[NonEmptyList[A]] =
    map2(fa, F.defer(listOf(fa)))(NonEmptyList(_, _))
@johnynek
Copy link
Contributor Author

johnynek commented Jun 3, 2020

That said, I can basically only see these as useful for parsers, so I am not sure we should bother adding it. On the other (other) hand, having this method here means you can code a lot of parser code against just Alternative and Defer and then you could share parsers more easily.

@LukaJCB
Copy link
Member

LukaJCB commented Jun 3, 2020

Possibly related to #3446

@djspiewak
Copy link
Member

I wrote a very long diatribe on these functions here: scalaz/scalaz#1097 (comment)

@johnynek
Copy link
Contributor Author

Daniel, I don't think I agree. you claim there are only two implementations (really they are both familes of the same:

val count: Int = ??? // any value will do here
def many(fa: F[A]): F[List[A]] = fa map { a => List.fill(count)(a) }

That is not what many actually does since you are ignoring the role of combineK. So clearly there are more implementations that the one you claim.

My implementations above rule out the concerns you had about non-termination because they always terminate due to using Defer. There is no Defer[F] for the kinds of strict data structures that cause a problem (there is no Defer[Option] or Defer[List] or other strict data structures we think of that have an Alternative[F] implementation).

I can't see an F that has both Defer[F] and Alternative[F] that is problematic at the moment. Can you? Certainly the main use of these functions are for parsers (I think they were introduced as such, but I can be mistaken).

My initial motivation was to write code that could generate both the Parser[A] and a Gen[A] with the same generic code, but you can't use many/some for Gen, there is a different approach there (repeatA with some Gen[Int]).

The List[A] vs some lazy structure, I think is beside the point, the laziness is in the F[_] not in the List[_] part.

I think the bottom line is that is just isn't very common at all to have both Defer and Alternative, so I think that is the key reason. I don't think I see any relevant reasons (once Defer has entered the picture) in your linked comment above.

That said, I do think Defer[F] still has a lot of unexplored space. In Haskell, everything is Defer[F] because the whole language is lazy, so it obscures where this concept is being used. I think by exploring it more we can probably find a few more use cases in scala where we can write more general code that has so far been pushed up to things like IO, or into one-offs using Eval.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants
@djspiewak @johnynek @LukaJCB and others