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

Re-introducing `Maybe.isNothing` #164

Closed
wants to merge 2 commits into
base: master
from

Conversation

Projects
None yet
4 participants
@jvoigtlaender
Contributor

jvoigtlaender commented Feb 7, 2015

One motivating example:

dblclicks : Time -> Signal ()
dblclicks d =
  let step t' s = case s of
                    Nothing -> Just t'
                    Just t  -> if t'-t < d then Nothing else Just t'
  in map (always ())
         (filter isNothing Nothing
                 (foldp step Nothing
                        (map fst (timestamp Mouse.clicks))))

It's a pain to have to write something like (\m -> case m of {Nothing -> True; _ -> False}) instead of isNothing above. (Update: That one-line inline definition will not even be valid syntax in Elm 0.16 anymore, since support for bracketed case expressions is being removed. This only makes it more painful to not have a function isNothing readily available.)

One possible rebuttal:

"But you could write ((==) Nothing) instead of the above explicit lambda-expression with pattern-matching."

My answer: That's not really good in general. It pretends that (==) works okay on all types (note that isNothing : Maybe a -> Bool is polymorphic in a). But in the future, to prevent runtime errors like that arising from identity == (\x -> x), it might come to pass that the compiler restricts uses of (==). It would have to restrict them not only on function types, but also somehow on polymorphism (since any a could turn into a b->c). Then suddenly ((==) Nothing) would be less generally applicable than isNothing.

Another possible rebuttal:

"Uses of fromJust and isNothing smell bad. Pattern-matching should be used instead."

My answer: I'm not proposing to re-inroduce fromJust. I yet have to see evidence of a piece of code that uses isNothing (but not fromJust) and seems bad style because of that use of isNothing. Also my example above uses only isNothing, not fromJust. I don't know what there could be to dislike about the use of isNothing in there. (See also this post.)

A cheap argument from my side:

We do have List.isEmpty (but not isNotEmpty, head : [a] -> a, and tail : [a] -> [a]) in the standard lib. The consistent thing to do w.r.t. Maybe is to have Maybe.isNothing (but not isJust and fromJust : Maybe a -> a) in the standard lib.

Evidence from other people's projects:

Searching GitHub gives the following places where Elm users have felt a need to introduce isNothing in their own code.

(Disclosure: Two of the above are students of mine. I don't think that is a relevant bias though.)

In addition, there are various GitHub hits where Elm users have used isNothing without defining it themselves. Apparently these projects are not yet upgraded from 0.13 to 0.14. If they were, maybe not all of these uses could be replaced by pattern-matching without pain, so at least in some of these cases it would be likely that these people would also start introducing their own implementation of isNothing:

I don't think it is possible to dismiss all the uses above with "isNothing is bad style, use pattern-matching instead".

Note that it is also well possible that additional uses exist where people have simply chosen a different name but implemented the same functionality.

About the process here

I know that the proper process to suggest an addition to the standard lib now is to first create a new package like elm-maybe-extras, put the new function there, wait a while to see whether it gets used. But let's be realistic. For a simple function like Maybe.isNothing, almost nobody will make the effort to add the required line to elm-package.json and add the required line to import the extra module into their code, just to be able to use that simple function which can just as easily be defined in one's own code. So what would happen is that the extra package would not get used but still we would see the proliferation of repeated definitions of isNothing in different people's projects. The only way I see to prevent such redundancy is to add isNothing right to the standard lib.

@jvoigtlaender

This comment has been minimized.

Show comment
Hide comment
@jvoigtlaender

jvoigtlaender Mar 11, 2015

Contributor

Can I bump this again? I'm still lacking any clue about what is considered harmful about isNothing. And as expressed above, pushing people into either redundantly re-defining it again and again, or into using something like ((==) Nothing), will most likely be regretted down the road. (Also, there seems to be no recommendation to use ((==) []) instead of isEmpty in the list case.)

Contributor

jvoigtlaender commented Mar 11, 2015

Can I bump this again? I'm still lacking any clue about what is considered harmful about isNothing. And as expressed above, pushing people into either redundantly re-defining it again and again, or into using something like ((==) Nothing), will most likely be regretted down the road. (Also, there seems to be no recommendation to use ((==) []) instead of isEmpty in the list case.)

@rtfeldman

This comment has been minimized.

Show comment
Hide comment
@rtfeldman

rtfeldman Jun 11, 2015

Member

This seems useful and harmless. +1 in my book.

Member

rtfeldman commented Jun 11, 2015

This seems useful and harmless. +1 in my book.

@mgold

This comment has been minimized.

Show comment
Hide comment
@mgold

mgold Jun 11, 2015

Contributor

Seems harmless. filterMap handles a lot of common cases but the double clicks example shows that it's not a silver bullet.

Contributor

mgold commented Jun 11, 2015

Seems harmless. filterMap handles a lot of common cases but the double clicks example shows that it's not a silver bullet.

Merge branch 'master' into isNothing
Conflicts:
	src/Maybe.elm
@jvoigtlaender

This comment has been minimized.

Show comment
Hide comment
@jvoigtlaender
Contributor

jvoigtlaender commented Sep 11, 2015

@evancz evancz closed this Sep 11, 2015

@evancz

This comment has been minimized.

Show comment
Hide comment
@evancz

evancz Sep 11, 2015

Member

The process is to go through *-extra, which it looks like has happened here.

I'd like to see the arguments for why things are useful be folded into that process. So when it comes time to review the list and maybe and result and whatever else libraries, we have all that stuff easily accessible. I am not sure if that happened in this case, so I'll add it to the meta issue. In the future, try to put it in the extra process though.

Member

evancz commented Sep 11, 2015

The process is to go through *-extra, which it looks like has happened here.

I'd like to see the arguments for why things are useful be folded into that process. So when it comes time to review the list and maybe and result and whatever else libraries, we have all that stuff easily accessible. I am not sure if that happened in this case, so I'll add it to the meta issue. In the future, try to put it in the extra process though.

@evancz evancz referenced this pull request Sep 11, 2015

Open

API Ideas #322

@jvoigtlaender jvoigtlaender deleted the jvoigtlaender:isNothing branch Sep 11, 2015

@mgold

This comment has been minimized.

Show comment
Hide comment
@mgold

mgold Sep 11, 2015

Contributor

I think that it only makes sense to have either both isJust and isNothing, or neither. They do come in handy when you don't want to do a pattern match.

Contributor

mgold commented Sep 11, 2015

I think that it only makes sense to have either both isJust and isNothing, or neither. They do come in handy when you don't want to do a pattern match.

@jvoigtlaender

This comment has been minimized.

Show comment
Hide comment
@jvoigtlaender

jvoigtlaender Sep 11, 2015

Contributor

And yet we have only List.isEmpty, not also List.containsSomething.

I'm not sure Maybe.isNothing and Maybe.isJust are equally useful.

What is an example where one would prefer isJust over a pattern match (and over isNothing)?

Contributor

jvoigtlaender commented Sep 11, 2015

And yet we have only List.isEmpty, not also List.containsSomething.

I'm not sure Maybe.isNothing and Maybe.isJust are equally useful.

What is an example where one would prefer isJust over a pattern match (and over isNothing)?

@mgold

This comment has been minimized.

Show comment
Hide comment
@mgold

mgold Sep 12, 2015

Contributor

Okay, that's an interesting point. Another function that is sometimes useful is dropNothings : List (Maybe a) -> List a but you can usually work around that with List.concatMap.

Contributor

mgold commented Sep 12, 2015

Okay, that's an interesting point. Another function that is sometimes useful is dropNothings : List (Maybe a) -> List a but you can usually work around that with List.concatMap.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment