Mark partial functions as such

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
30 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Re: Mark partial functions as such

Haskell - Libraries mailing list
(Sending this again, as I forgot to include the list)

Hi Richard,

I think that's a good idea!

What about typeclass methods where totality / partiality depends on the instance like Foldable's foldl1? What do we mark partial in this case? The method declaration? The instance? Both?

Cheers,
Simon

Am Fr., 31. Aug. 2018 um 02:13 Uhr schrieb Richard Eisenberg <[hidden email]>:
Just to clarify here: all I mean is that we should include the word "Partial" in the Haddock documentation -- no deprecation or warning, just documentation.

Richard

> On Aug 30, 2018, at 8:10 PM, Richard Eisenberg <[hidden email]> wrote:
>
> Proposal: Mark partial functions in `base` as partial
>
> Motivation: I'm about to teach Haskell to a classful of beginners. In my experience, they will soon reach for functions like `head` and `tail`, because pattern-matching is foreign to them. I would love just to be able to say "Don't use partial functions", but many students will not easily be able to tell partial functions from total ones.
>
> I do expect this problem to work itself out rather quickly, and then students will be able to identify partial functions, but loudly marking partial functions as partial seems like a small service to everyone and a bigger one to newbies. I don't see any downsides.
>
> Thoughts?
>
> Thanks,
> Richard
> _______________________________________________
> Libraries mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Mark partial functions as such

Henrik Nilsson-2
In reply to this post by Richard Eisenberg-4
Hi,

Richard Eisenberg wrote:

 > Maybe here's a concrete example:
 >
 > > -- | /Contains a call to 'error'./ Extract the first element of a
 > list, which must be non-empty.
 > > head                    :: [a] -> a
 >
 > In the end, it's the call to error that I want noted.

Yes, whether the code of a function directly or indirectly calls "error"
is well-defined property that could be documented.

But note that this does not coincide with the following:

 > > I think we want something like "partial even given input you can
 > > successfully DeepSeq"
 >
 > That's the specification of the feature I'm after

Consider e.g.

    apply f x = f x

As e.g.

    apply head [] == _|_

we'd have to conclude by the above definition that "apply" is partial.
But it clearly does not "call error".

Just to be clear, this does not correspond to how I understand
partiality. Lots of higher order functions, like "map", then would have
to called partial. And I am not sure that would be so helpful for
the purpose of alerting (new) programmers to functions that one
might argue should be avoided.

So maybe something very clear and easy to understand, such as "contains
call to error" is the best approach.

Best,

/Henrik



This message and any attachment are intended solely for the addressee
and may contain confidential information. If you have received this
message in error, please contact the sender and delete the email and
attachment.

Any views or opinions expressed by the author of this email do not
necessarily reflect the views of the University of Nottingham. Email
communications with the University of Nottingham may be monitored
where permitted by law.




_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Mark partial functions as such

Ryan Trinkle-3
This is probably not really for the libraries list, but in the same vein as this discussion, I think it would be extremely helpful to have a way of banning functions that does *not* require changing the upstream library.  I would be thrilled to have a machine-checked ban on use of the 'head', 'tail', etc.

On Fri, Aug 31, 2018 at 11:36 AM Henrik Nilsson <[hidden email]> wrote:
Hi,

Richard Eisenberg wrote:

 > Maybe here's a concrete example:
 >
 > > -- | /Contains a call to 'error'./ Extract the first element of a
 > list, which must be non-empty.
 > > head                    :: [a] -> a
 >
 > In the end, it's the call to error that I want noted.

Yes, whether the code of a function directly or indirectly calls "error"
is well-defined property that could be documented.

But note that this does not coincide with the following:

 > > I think we want something like "partial even given input you can
 > > successfully DeepSeq"
 >
 > That's the specification of the feature I'm after

Consider e.g.

    apply f x = f x

As e.g.

    apply head [] == _|_

we'd have to conclude by the above definition that "apply" is partial.
But it clearly does not "call error".

Just to be clear, this does not correspond to how I understand
partiality. Lots of higher order functions, like "map", then would have
to called partial. And I am not sure that would be so helpful for
the purpose of alerting (new) programmers to functions that one
might argue should be avoided.

So maybe something very clear and easy to understand, such as "contains
call to error" is the best approach.

Best,

/Henrik



This message and any attachment are intended solely for the addressee
and may contain confidential information. If you have received this
message in error, please contact the sender and delete the email and
attachment.

Any views or opinions expressed by the author of this email do not
necessarily reflect the views of the University of Nottingham. Email
communications with the University of Nottingham may be monitored
where permitted by law.




_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Mark partial functions as such

Henning Thielemann

On Fri, 31 Aug 2018, Ryan Trinkle wrote:

> This is probably not really for the libraries list, but in the same vein
> as this discussion, I think it would be extremely helpful to have a way
> of banning functions that does *not* require changing the upstream
> library.  I would be thrilled to have a machine-checked ban on use of
> the 'head', 'tail', etc.

So far I have HLint rules to ban them. Unfortunately, they do not work
transitively. People have already proposed a TotalHaskell pragma
analogously to SafeHaskell.
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Mark partial functions as such

Tikhon Jelvis
Deeper questions of partiality aside, if a function can throw exceptions, the documentation should spell this out *explicitly*, ideally also specifying what the type of the exception may be. To me, this is a *minimum* standard to expect from documentation in any language with exceptions.

Whenever I write a function that might error out in my work code, I always write a separate paragraph explaining this. Usually it reads something like "Raises an error if these conditions aren't met" for whatever preconditions the function has. I don't know if this documentation requirement is in our style guide, but if it isn't I should put it in :).

This is definitely something we should have in the documentation for base. I would document head something like this:

> Return the first element of the given list.

> Raises an 'ErrorCall' exception if the list is empty.

I could see a case for putting less emphasis on the fact that it's a specific exception—exceptions in pure functions are a bit weird—but the basic structure would still be the same: a distinct part of the documentation calling out the error condition explicitly.


On Fri, Aug 31, 2018, 17:54 Henning Thielemann <[hidden email]> wrote:

On Fri, 31 Aug 2018, Ryan Trinkle wrote:

> This is probably not really for the libraries list, but in the same vein
> as this discussion, I think it would be extremely helpful to have a way
> of banning functions that does *not* require changing the upstream
> library.  I would be thrilled to have a machine-checked ban on use of
> the 'head', 'tail', etc.

So far I have HLint rules to ban them. Unfortunately, they do not work
transitively. People have already proposed a TotalHaskell pragma
analogously to SafeHaskell._______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Mark partial functions as such

Oliver Charles-3
On Fri, Aug 31, 2018 at 5:21 PM Tikhon Jelvis <[hidden email]> wrote:

> Deeper questions of partiality aside, if a function can throw exceptions, the documentation should spell this out *explicitly*, ideally also specifying what the type of the exception may be. To me, this is a *minimum* standard to expect from documentation in any language with exceptions.

Is this to be applied transitively? It has to be, to meet your
criteria, but this is a fairly unrealistic expectation to put on
library authors. If it's not applied transitively, then the
documentation creates a false sense of security - "catch these
exceptions that *I* throw and you're good!". I really think this part
of exceptions is a tooling problem that we have to solve. Haddock
should be responsible for figuring this out.

Ollie
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Mark partial functions as such

Henning Thielemann

On Fri, 31 Aug 2018, Oliver Charles wrote:

> On Fri, Aug 31, 2018 at 5:21 PM Tikhon Jelvis <[hidden email]> wrote:
>
>> Deeper questions of partiality aside, if a function can throw
>> exceptions, the documentation should spell this out *explicitly*,
>> ideally also specifying what the type of the exception may be. To me,
>> this is a *minimum* standard to expect from documentation in any
>> language with exceptions.

'error' is not an exception, it is an undefined value. 'error' is only a
debugging convenience that would otherwise be an infinite loop. It should
not be necessary to distinguish them in production code.
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Mark partial functions as such

Bardur Arantsson-2
In reply to this post by Oliver Charles-3
On 31/08/2018 18.59, Oliver Charles wrote:

> On Fri, Aug 31, 2018 at 5:21 PM Tikhon Jelvis <[hidden email]> wrote:
>
>> Deeper questions of partiality aside, if a function can throw exceptions, the documentation should spell this out *explicitly*, ideally also specifying what the type of the exception may be. To me, this is a *minimum* standard to expect from documentation in any language with exceptions.
>
> Is this to be applied transitively? It has to be, to meet your
> criteria, but this is a fairly unrealistic expectation to put on
> library authors. If it's not applied transitively, then the
> documentation creates a false sense of security - "catch these
> exceptions that *I* throw and you're good!". I really think this part
> of exceptions is a tooling problem that we have to solve. Haddock
> should be responsible for figuring this out.
>

Not to mention the issues of "may throw" declarations for higher-order
functions... (Java checked exceptions are basically broken[1] because of
this. Well, this + the variance issues arising from inheritance and
method signatures, but obviously Haskell doesn't have inheritance, so...)

Regards,

[1] They even break "catch" because everybody is forced to wrap
"checked" exceptions in a RuntimeException if signatures don't specify
"may throw anything", so you *also* have to check for wrapped exceptions
in "catch" clauses. Anyway...

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Mark partial functions as such

Tikhon Jelvis
This is a question of documentation, not type design. You don't have to consider what exceptions your transitive dependencies might throw—you need to understand what inputs *do* cause your function to fail. If you use head in a safe way or have a call to error in an unreachable case, you shouldn't say anything. On the other hand, if your function fails when the inputs aren't relatively prime, you should document this regardless of whether the failure is an exception you throw explicitly, a result of a partial pattern match or a division by zero four layers of indirection away.

I definitely expect the author of a function to understand what inputs cause that function to fail. If you don't understand this, you simply don't understand the code you wrote. (Luckily, QuickCheck will probably find any edge cases you missed when writing the function.)

Thinking about it a bit more, there's nothing specific to exceptions here. If your code loops forever when the lengths of the inputs sum to a multiple of seven, that's pretty handy to know from the documentation! 

I would also expect the same style of documentation even for errors expressed in the types with whatever your favorite generalization of Either happens to be.

On Fri, Aug 31, 2018, 19:07 Bardur Arantsson <[hidden email]> wrote:
On 31/08/2018 18.59, Oliver Charles wrote:
> On Fri, Aug 31, 2018 at 5:21 PM Tikhon Jelvis <[hidden email]> wrote:
>
>> Deeper questions of partiality aside, if a function can throw exceptions, the documentation should spell this out *explicitly*, ideally also specifying what the type of the exception may be. To me, this is a *minimum* standard to expect from documentation in any language with exceptions.
>
> Is this to be applied transitively? It has to be, to meet your
> criteria, but this is a fairly unrealistic expectation to put on
> library authors. If it's not applied transitively, then the
> documentation creates a false sense of security - "catch these
> exceptions that *I* throw and you're good!". I really think this part
> of exceptions is a tooling problem that we have to solve. Haddock
> should be responsible for figuring this out.
>

Not to mention the issues of "may throw" declarations for higher-order
functions... (Java checked exceptions are basically broken[1] because of
this. Well, this + the variance issues arising from inheritance and
method signatures, but obviously Haskell doesn't have inheritance, so...)

Regards,

[1] They even break "catch" because everybody is forced to wrap
"checked" exceptions in a RuntimeException if signatures don't specify
"may throw anything", so you *also* have to check for wrapped exceptions
in "catch" clauses. Anyway...

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Mark partial functions as such

Bardur Arantsson-2
On 31/08/2018 21.14, Tikhon Jelvis wrote:

> This is a question of documentation, not type design. You don't have to
> consider what exceptions your transitive dependencies might throw—you
> need to understand what inputs *do* cause your function to fail. If you
> use head in a safe way or have a call to error in an unreachable case,
> you shouldn't say anything. On the other hand, if your function fails
> when the inputs aren't relatively prime, you should document this
> regardless of whether the failure is an exception you throw explicitly,
> a result of a partial pattern match or a division by zero four layers of
> indirection away.
>
> I definitely expect the author of a function to understand what inputs
> cause that function to fail. If you don't understand this, you simply
> don't understand the code you wrote. (Luckily, QuickCheck will probably
> find any edge cases you missed when writing the function.)
>
> Thinking about it a bit more, there's nothing specific to exceptions
> here. If your code loops forever when the lengths of the inputs sum to a
> multiple of seven, that's pretty handy to know from the documentation! 
>
> I would also expect the same style of documentation even for errors
> expressed in the types with whatever your favorite generalization of
> Either happens to be.
>

Oh, of course, these are good points. My point was simply that it's
often a little bit complicated to *document* this in a simple easy to
understand way.

Regards,

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
12