-
Notifications
You must be signed in to change notification settings - Fork 139
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
Add total counterparts to partial functions, such as head
.
#479
Comments
Specifically to the choice between
P. S.There is |
There is already Same could be applied to Also it is easier to read and match with the partial counter part in the doc:
Similar to how we have |
I agree that consistency is a possible way to refine the ordering of candidate names. But thumbs (either up or down) only distract — arguments feed the soul. And ideas on sections marked with the code «TODO» would be even better. I @kindaro am accountable for this overview and I shall keep this message up to date. Give me your arguments and I shall write them in. Then we shall see. thesisConsistency with status: in researchfor
against
|
Another possible principle of naming is «… or nothing», like |
Generating documentation from property checks seems to be technically infeasible. Right now the code we have is packaged as it is — there are no instruments to release generated code, much less to carefully patch automatically generated haddocks into handwritten code. However, we can try to generate checks from documentation. There are already instruments for this — the one I know is the We can however invent some kind of markup that is both human and machine friendly, put it into haddocks and then write a program that will parse our markup out of haddocks and write for us a test suite. This is conceptually simpler than what The idea of the markup is like so:
Example: -- | /O(1)/ First element.
--
-- This function is not defined on @fromList [ ]@. Its completion is 'vectorToMaybe'.
head :: Vector v a => v a -> a
{-# INLINE_FUSED head #-}
head v = v ! 0
-- | /O(1)/ Just the first element — or nothing when there are none.
--
-- This function is the completion of 'head'.
vectorToMaybe :: Vector v a => v a -> Maybe a
{-# INLINE_FUSED vectorToMaybe #-}
vectorToMaybe v = v !? 0 Here, the patterns Even better, maybe we can work with the «metadata» syntax already in I still need to think through a way of denoting sets more generally that is still human friendly. For some partial functions, like maybe There will also be a static check that all names in a given hard-coded list have checks generated for them. This is so that haddocks could not be broken by a future unsuspecting editor. |
On namingPrecedent of using
Beside identifier names are not English words. They come from some weird agglutinative language which borrows extremely liberally from English. On haddockHaddock first and foremost is a documentation tool. They are meant to be read by humans. Metadata idea is interesting but does anything except |
@Shimuuar As to naming, I added your arguments to the summary. But of course it is possible that I do not understand your point of view well enough, so let me know if I misinterpret you. That some people like their names mangled beyond recognition is sadly true but I myself loathe to do do that and I do not see an argument for it being a best practice. Can you make an argument that consistently mangled names are better for novices and moderately experienced people than less consistent names that are each clear by themselves? I accept that narrow experts prefer shorthand, the strongest example I know of being Mathematical Components for Coq, which are impossible to understand for anyone but an expert. But I for example work with maybe 5 different languages and a good dozen of frameworks, and I have to learn a few new ones every year, so for me mangled names are a hardship. I do not see the need to learn that weird agglutinative language you speak about — I think this is the biggest hoax of software engineering. We do not have to decide anything about names just yet. We can do some more research.
I am not sure I follow your logic. Examples and properties are exactly «machine-readable specification shoehorned into docstrings». Are you saying
Nothing except -- | /O(1)/ First element.
--
-- @partial
-- @undefined @fromList [ ]@
-- @completion 'vectorToMaybe'
head :: Vector v a => v a -> a
{-# INLINE_FUSED head #-}
head v = v ! 0
-- | /O(1)/ Just the first element — or nothing when there are none.
--
-- @completes 'head'
vectorToMaybe :: Vector v a => v a -> Maybe a
{-# INLINE_FUSED vectorToMaybe #-}
vectorToMaybe v = v !? 0 What do you think? Patching …Turns out the |
IMO "completion" is not good terminology for documentation. I've never seen it being used in the context of Haskell before and it's not self-explanatory, so I doubt most people will know what it means. I would just say "total version"/"partial version" or "total counterpart"/"partial counterpart", that way it's clear what you're talking about. |
I have never seen it either. I was thinking that giving a name to this correspondence itself, and not only to its outcome, would add conceptual clarity. So, I picked «completion». But I am not on the seventh heaven of happiness about it. How would you call the process of making a total function out of a partial function? |
Ah, you should have said that you made it up! I'd just say "making the total version/counterpart". I don't think it helps to invent a word for it. |
This is getting nowhere. But I think it would be useful to decide on naming conventions for total counterparts. From cursory haddock search it seems there are 3 existing conventions:
If there're other convention which I missed please bring them up. I vote +1 on |
@Shimuuar My vote is:
|
+1 for |
So there's an unanimous support for the |
I love it! It took us only 4 short messages to decide on the naming scheme. That is what I call efficiency! 😁 |
I grepped Hackage:
So I'd say that |
@Bodigrim How does one grep Hackage? I believe «maybe …» is the best choice. So say what. I am going to write whichever names I want and then before merging code into |
@konsumlamm Actually, turns out that my use of the word «completion» coincides with common usage:
One of the design possibilities I am weighing is to wield If you have any specific suggestions surely do tell me. Otherwise I offer to wait until the design is clarified and a few examples are implemented. Then we shall better see what looks good and what does not. Agreeable? |
status update
|
It would save everyone's time and effort if you stick with agreed upon conventions. If you create PR with different naming and start arguing that functions should be named this or that I'll simply close PR.
But that makes it quite poor name. We aren't completing function which undefined on pats of its domain. We create functions which report errors differently. I think simple
We can't. It's not implemented. If you want to go and implement such feature. Please do, it's very neat feature and would be nice to have. |
https://hackage-search.serokell.io/ supports regexps, I use it all the time. I linked the regexps I used above.
There is no particular hurry. If you wish to convince us for a different naming scheme, you can give it a try, but I think I've made up my mind already. I tend to think that coming up with names is actually the biggest challenge here, the implementation per se is rather trivial. So I'd rather settle on them before writing any code. I personally would not mind though if you raise a draft PR with a disclaimer "All function names are tentative and are discussed in #479", but I do not quite recommend it. I'm not sure what we want to do about partial functions like
but is it worth its salt? If one is conscious to avoid partial functions, they can use the normal |
After some thought I think
|
Another approach is
but also Going further, are we looking to introduce |
We should compile list of partial functions. It would be easier to decide what should we do then |
As noticed by @kindaro above, |
This is the overview of the programme to add total counterparts to partial functions, such as
head
.I @kindaro am accountable for this overview and I shall keep this message up to date. If something is off, comment; if I am not answering, send me an electronic letter; if I am not answering again, take over.
We estimate that there is 50% likelihood to get this done in 70 hours of work or less. This number is computed by adding mean values of subjective probability distributions of time it would take to get each of the following tasks done:
I heartily welcome the kind reader to comment on the sections of this message marked with the code «TODO».
status: request for comments
Implementation will begin when consensus with the maintainers is reached and the design is clarified.
motivation
There are two aspects to this programme:
These two aspects translate into two goals that seem to be largely independent.
An optional goal is to offer a clear way of managing partial functions that can then be scaled to other core libraries.
mathematical ground
definitions
As an example of a naming issue called the «mathematical red herring principle», things that are called «partial functions» and «unsafe functions» in the Haskell community are not functions, and «total function» is needless tautology.
So, «partial function» is a convenient but misleading shortcut for «relation that reflects distinctions».
This is important to keep in mind because it means that any theory of functions is not going to be a true description of a definition that wields any partial functions. Many principles of reasoning about Haskell programs will be invalidated. See for example Fast and Loose Reasoning is Morally Correct. Unsafe functions cannot even be modelled as general relations — rather, a theory of automata will need to be wielded, — so they will not be looked at. It seems to be the consensus that the best solution for them is isolation, as in #361.
partial map classifier
From the classical perspective, any partial function f: A ⇸ B can be turned into a function f*: A → B + 1 with the target A + 1, which in Haskell can be modelled by
Maybe A
. This typeMaybe A
would be called «partial map classifier» in Mathematics.However, constructively we cannot really say if an arbitrary computation will terminate. For example, we do not know if a hailstone sequence starting from a big enough number will terminate. Technically speaking, each sound termination analyzer is incomplete.
Nevertheless, we hope to be able to say for any computation found in the core libraries and specifically
vector
either that:Then, we can turn those partial functions for which we are able to say so into functions by putting the inputs on which they will not terminate to
Nothing
. We shall call this process and its outcome «completion». Thanks to the classical theory, we know that every function has at most one completion, so this is not ambiguous. We can even say that completion is a partial function from partial functions to functions, however sadly not computable.example
This partial function from
Data.Vector.Generic
:— Is completed to this function:
design
A list of partial functions in
vector
is already compiled for us inrio
. There are 35 of them. None of them have a completion yet (TODO look again).For the sake of sustainability, automated checks should be added. Given a pair of a partial function and its completion:
Nothing
.Just
.In the ideal, these two sets should exhaust the source.
In the ideal, these checks will be defined in such a way that human friendly documentation can also be generated, then somehow such documentation should make its way to haddocks. This would ensure sustainability of documentation as well as code itself.
(TODO think of a way to get great automated checks and documentation)
naming
All new names shall be either:
Arbitrary abbreviations and shorthands will not be allowed. More specific names will be picked rather than more general ones.
(TODO draft specific suggestions)
scope
Only definitions exported from
Data.Vector
are to be completed at this time. (TODO what other definitions should we work on?) Unsafe definitions that cannot be trivially modelled as relations will not be looked at — their completion is not grounded in Mathematics; they are out of scope.future work
In the ideal, we should offer two modules: the one would export only functions and the other would export only partial functions. That the way we mark definitions as either lets us hope that in future work such modules can be generated automatically. This would complete the solution of the aspect № 2.
chunks of work
The work will be done in working, fully done chunks, split as follows:
head
inData.Vector.Generic
with basic checks and documentation.prior art
(TODO mention other conversations where similar programmes were talked about)
base
: Add {-# WARNING #-} to Data.List.{head,tail} core-libraries-committee#87.The text was updated successfully, but these errors were encountered: