Informal discussion about the progression of `base`

What about NonEmpty? :stuck_out_tongue:

2 Likes

I’m not sure what you mean.

I suppose you could add a warning,
like was done with head and tail. :sweat_smile:

Yes, I think if max/minimumMaybe are added then it makes sense to add a warning to max/minimum.

1 Like
λ> maximum []
*** Exception: Prelude.maximum: empty list

NonEmptyList would not explode at run time (I understand there are other problems with this). It would be a classic “parse, do not validate” moment.

I’m still not sure what you mean and I’m not sure if you’re even responding to me! But if you are, then I guess I can elaborate: the problem with max/minimum is not that they’re partial on all Foldable instances but that they’re partial on some.

1 Like

Am not a fan of such warnings, unless they are disabled by default. The head/tail warnings are even less useful, since the ‘error’ is a fundamental property, not a bug.

Yes, I’m not sure if adding warnings would pass CLC vote, but I’m almost certain adding max/minimumMaybe would.

It’d be better if the warning system could add warnings to specific instances. I don’t think it can currently and I couldn’t figure out how to work around it.

1 Like

It’s not a problem with specific instances. The instances for which it’s safe can have Foldable1 instances too, and they should use max/minimum1, which has a constraint on that type class. (However, I don’t think max/minimum1 exist where Foldable1 is defined, so there’s a hole in the ecosystem there.)

For now, I suggest only the smallest set of changes needed to avoid:

…thereby alleviating the need for extra “special” classes like PartialEq and PartialOrd.

Why so cautious? Because Haskell usually has no notion of evaluation order e.g. (x + y) == (y + x), so (+) should be commutative…and unfortunately, not (always) so for floating-point values:

So that “large pile of floating-point changes” would require careful scrutiny (and the time to do so) to determine which of them are “Haskell-compatible”.

Perhaps the design of the R language (which is also nonstrict) could prove useful in such a task.

It’s more about what can we do to incrementally evolve Haskell without breaking anyone’s code and making things nicer for everyone. I do feel like we’re maybe talking past each other, but that’s ok.

1 Like

I agree with several of the things already said. Things like getting Text in place of String, vector, the idea of a better situation around Show, and more.

There is one idea that I haven’t seen mentioned:
A named version of every operator.

Purescript does this, actually it is enforced, and it would be great for us to steal that idea at least for base. It is very helpful when talking about code, be that pair programming, or something else.

8 Likes

If you do make |> and <| the obvious definitions of one-side <|>, they end up being cons and snoc. Something to that…

1 Like

containers already defines both of those operators, with precisely those meanings!

4 Likes

Sounds like a lock then!

(|>) :: Alternative f => a -> f a -> f a
a |> fa = pure a <|> fa

(<|) :: Alternative f => f a -> a -> f a
fa <| a = fa <|> pure a
2 Likes

This is in my fantasy base, along with an additional rule:

Class should define named functions, and operators should be defined separately

-- Like this:
class Semigroup a where
     append :: a -> a -> a
(<>) = append

-- Not like this:
class Semigroup a where
     (<>) :: a -> a -> a

The Num class is a particularly bad offender as well.

The intent is to make it easier for small operators like + and * to be re-used, instead of inventing operators like |+| or monsters like <<*>>. It is a lot easier to hide (conflicting) operators when they aren’t a part of a class definition.

3 Likes

I actually disagree with that. I understand that a name is usefull to communicate with others but I see most operator as syntax and pretty much never need their name when I read an expression with operator.

For example in C++ in object->method(a,b) I don’t need a name for -> , (..) and ,. I just read it.
It is the same with Haskell construct like (,) <$> a <*> b. I just SEE what it does (even though now a day I prefer to use liftA2 (,) . Having names in my head will just confuses me.

2 Likes

That only works if you see operators as syntax. :slight_smile: