there's also the camp of "I refactored a [a] into a (b, [a]) and it compiled, and I now get length xs == 1 always"
Isn't this an issue orthogonal to the above? Whereas earlier it was about unexpected time complexity of Foldable, now this is a case of unexpected instances of Foldablethat the compiler should have but didn't report as type errors?
The latter isn't your fault.
But if you think the client of your library needs reminding of perilous Foldable instances, they will appreciate the effort you took to add that reminder in your docs.
even if I highlight it my coworker(or me one week later!) can easily ignore/forget the docs - anything that isn't enforced but merely a suggestion will eventually be "gotten wrong"
it's not my fault that the instances are there, but by providing explicit applications I can do something to avoid unexpectedly using them - much like how it's usually better when possible to do explicit matches on all constructors vs a _ match, so that when you add a new constructor to your datatype you get reminded by the compiler to write proper logic for it wherever you're using the datatype
even if I highlight it my coworker(or me one week later!) can easily ignore/forget the docs - anything that isn't enforced but merely a suggestion will eventually be "gotten wrong"
It sounds like you're dead set on this novel idea of "forcing type application," in which case I'll refrain from giving more suggestions on what else you could do.
I will say, though, your work environment sounds quite dysfunctional if communicating critical information, whether via docs or otherwise, cuts so against the grain.
this is not about people not knowing stuff - it's about people forgetting stuff, and even more than that about minimising how much one has to actively think about while writing a program
it's not my fault that the instances are there, but by providing explicit applications I can do something to avoid unexpectedly using them - much like how it's usually better when possible to do explicit matches on all constructors vs a _ match, so that when you add a new constructor to your datatype you get reminded by the compiler to write proper logic for it wherever you're using the datatype
This is a false analogy. Yes, the compiler warns of missing pattern matches when new constructors get added.
Ever notice what happens when a haskell beginner enters not at the repl? They get the Show instance not found error for the type of a function.
An instance that should be there isn't, resulting in compiler dyspepsia just like when pattern matching that should be there isn't. That is the true analogy.
Also you aren't "providing explicit applications." Here you are mandating explicit applications by revoking type class instance inference which essentially means getting rid of all of type classes entirely. Far from giving something, you actually want to take things away from the status quo.
Are you alluding to a problem with OverlappingInstances? Or are you trying to mitigate the Foldable instance problem for tuples? The greater clarity you bring to your problem the easier it is to find a proper solution instead of one that brings a raft of new problems.
It sounds like the latter: there is a Foldable instance for tuples that you'd somehow want to suppress. And so the solution you're reaching for is to force type applications.
There are other solutions.
This proposal about "forcing type applications" will absolutely require hacking on the ghc compiler to implement.
This is a false analogy. Yes, the compiler warns of missing pattern matches when new constructors get added.
I don't see how it's any different from the pov of "this is something the compiler can handle instead of me".
Also you aren't "providing explicit applications." Here you are **mandating** explicit applications by **revoking** type class instance inference which essentially means getting rid of all of type classes entirely. Far from giving something, you actually want to take things away from the status quo.
Just because I'm doing so for one function, doesn't mean I am going to do so for every function in existence (I'm not writing (+) @Int 5 3!!). I would be writing Elm or Go instead, if I wanted to do that.
Are you alluding to a problem with OverlappingInstances? Or are you trying to mitigate the `Foldable` instance problem for tuples? The greater clarity you bring to your problem the easier it is to find a proper solution instead of one that brings a raft of new problems.
It sounds like the latter: there is a Foldable instance for tuples that you'd somehow want to suppress. And so the solution you're reaching for is to force type applications.
There are other solutions.
Would you argue Maybe also shouldn't have Foldable? Because in my original case the two concrete uses are of Foldable [] and Foldable Maybe - and I was not originally trying to prevent anything - it was just clearer to write @Maybe or @[] rather than spend time trying to figure out what type is being used in a code review (this is coming from someone else btw, not me)
This proposal about "forcing type applications" will absolutely require hacking on the ghc compiler to implement.
I am not proposing to change the compiler or anything like that - I was only asking if I can do this thing (and I even got a solution that is good enough for my use case).
Just because I'm doing so for one function, doesn't mean I am going to do so for every function in existence (I'm not writing (+) @Int 5 3!!). I would be writing Elm or Go instead, if I wanted to do that.
Agreed. But you still need to be clear with your use of plain language. You are mandating type application for a small set of functions you’ve written. You aren't providing anything. You are demanding that the client of those functions write those type applications. It is the client who is doing the providing because you have insisted on it.
Would you argue Maybe also shouldn't have Foldable? Because in my original case the two concrete uses are of Foldable [] and Foldable Maybe - and I was not originally trying to prevent anything - it was just clearer to write @Maybe or @[] rather than spend time trying to figure out what type is being used in a code review (this is coming from someone else btw, not me)
This is what I mean about problem clarity.
Is this an issue of unclear instance resolution leading to poor code readability and maintainability? Because that's a problem of ad-hoc polymorphic code in general.
Poor code maintainability isn't the same problem as erroneous instance resolution that risks a runtime error. The latter cuts deeper because it jeopardizes the assurance that well-typed programs don't go wrong.
Would you argue Maybe also shouldn't have Foldable?
Why "also"? I haven't argued anything that can be construed as a lead-in to this question. If you're referring to the Foldable instance for tuples, that was seeking clarification from you because that was the example you gave earlier. You seem to allude that it is a problem so I wrote what I did hypothesizing on that assumption.
If you really want to know my opinion about Foldable instances, we can discuss in a different thread. I'm quite cognizant of the arguments pro and contra the FTP proposal.
I participated in this conversation in the spirit of nudging it back to X--the problem--rather than letting it fester on a fixation on Y--the attempted solution because as the record demonstrates, we have a classic XY problem on our hands: http://xyproblem.info/
I started talking about this as different reasons I could think of why you would want to be explicit about what instances you're using (this is what I understood from Why would you want to do that?)
I started talking about this as different reasons I could think of why you would want to do this (this is what I understood from Why would you want to do that?)
The "you" in the question was specific. It is a "you with whatever problem you are facing hic et nunc" rather than a hypothetical "you" in all possible worlds.
does anyone know of a way to force users of a function
f :: Foldable t => ...
to always useTypeApplications
? to specifyt
https://github.com/int-index/ghc-proposals/blob/visible-forall/proposals/0000-visible-forall.rst
:question:
omg vdq
nooo ghc 8.10 :sob: i'm on 8.8
thanks
wait it doesn't work
@Georgi Lyubenov // googleson78 https://kcsongor.github.io/ambiguous-tags/#an-ambiguous-smart-constructor
ah thanks, I knew I had seen that in his blog, but I didn't remember where/didn't find it
with ghc9
It only works with kinds for now
Namespacing problems coming from types written as expressions are not solved yet
or at least not decided upon
cool, the hack works in my case, thanks!
Why would you want to do that? It’s up to the client of your function to decide whether to leave instance resolution to the compiler.
for readability and maintainability
foldl1 expensiveOperation
is very different depending on if you have a[]
orMaybe
there's also the camp of "I refactored a
[a]
into a(b, [a])
and it compiled, and I now getlength xs == 1
always"(instead of
length . snd
which is what they want)it's a slightly more "thrifty" solution (not sure if right word) compared to manual specialisations for all the
t
s you want to use it forGeorgi Lyubenov // googleson78 said:
So highlight that point in the documentation of your library.
Georgi Lyubenov // googleson78 said:
Isn't this an issue orthogonal to the above? Whereas earlier it was about unexpected time complexity of
Foldable
, now this is a case of unexpected instances ofFoldable
that the compiler should have but didn't report as type errors?The latter isn't your fault.
But if you think the client of your library needs reminding of perilous
Foldable
instances, they will appreciate the effort you took to add that reminder in your docs.even if I highlight it my coworker(or me one week later!) can easily ignore/forget the docs - anything that isn't enforced but merely a suggestion will eventually be "gotten wrong"
it's not my fault that the instances are there, but by providing explicit applications I can do something to avoid unexpectedly using them - much like how it's usually better when possible to do explicit matches on all constructors vs a
_
match, so that when you add a new constructor to your datatype you get reminded by the compiler to write proper logic for it wherever you're using the datatypeit takes "cognitive load" off me, and puts it on the compiler instead
tbh if this was a public library I probably wouldn't do this! (or I would do it in some other way, e.g. not use Foldable)
but it's something that we've agreed upon for some specific functions at my workplace :sweat_smile: sorry if this was "missing critical information"
Georgi Lyubenov // googleson78 said:
It sounds like you're dead set on this novel idea of "forcing type application," in which case I'll refrain from giving more suggestions on what else you could do.
I will say, though, your work environment sounds quite dysfunctional if communicating critical information, whether via docs or otherwise, cuts so against the grain.
I don't see how communicating information helps the problem of "oops this happened by accident"
to me this is like saying we don't need a typechecker because you can simply write next to a function what kinds of arguments it takes and returns
this is not about people not knowing stuff - it's about people forgetting stuff, and even more than that about minimising how much one has to actively think about while writing a program
Georgi Lyubenov // googleson78 said:
This is a false analogy. Yes, the compiler warns of missing pattern matches when new constructors get added.
Ever notice what happens when a haskell beginner enters
not
at the repl? They get the Show instance not found error for the type of a function.An instance that should be there isn't, resulting in compiler dyspepsia just like when pattern matching that should be there isn't. That is the true analogy.
Also you aren't "providing explicit applications." Here you are mandating explicit applications by revoking type class instance inference which essentially means getting rid of all of type classes entirely. Far from giving something, you actually want to take things away from the status quo.
Are you alluding to a problem with OverlappingInstances? Or are you trying to mitigate the
Foldable
instance problem for tuples? The greater clarity you bring to your problem the easier it is to find a proper solution instead of one that brings a raft of new problems.It sounds like the latter: there is a Foldable instance for tuples that you'd somehow want to suppress. And so the solution you're reaching for is to force type applications.
There are other solutions.
This proposal about "forcing type applications" will absolutely require hacking on the ghc compiler to implement.
I don't see how it's any different from the pov of "this is something the compiler can handle instead of me".
Just because I'm doing so for one function, doesn't mean I am going to do so for every function in existence (I'm not writing
(+) @Int 5 3
!!). I would be writing Elm or Go instead, if I wanted to do that.Would you argue
Maybe
also shouldn't haveFoldable
? Because in my original case the two concrete uses are ofFoldable []
andFoldable Maybe
- and I was not originally trying to prevent anything - it was just clearer to write@Maybe
or@[]
rather than spend time trying to figure out what type is being used in a code review (this is coming from someone else btw, not me)I am not proposing to change the compiler or anything like that - I was only asking if I can do this thing (and I even got a solution that is good enough for my use case).
Georgi Lyubenov // googleson78 said:
Agreed. But you still need to be clear with your use of plain language. You are mandating type application for a small set of functions you’ve written. You aren't providing anything. You are demanding that the client of those functions write those type applications. It is the client who is doing the providing because you have insisted on it.
Georgi Lyubenov // googleson78 said:
This is what I mean about problem clarity.
Is this an issue of unclear instance resolution leading to poor code readability and maintainability? Because that's a problem of ad-hoc polymorphic code in general.
Poor code maintainability isn't the same problem as erroneous instance resolution that risks a runtime error. The latter cuts deeper because it jeopardizes the assurance that well-typed programs don't go wrong.
Why "also"? I haven't argued anything that can be construed as a lead-in to this question. If you're referring to the Foldable instance for tuples, that was seeking clarification from you because that was the example you gave earlier. You seem to allude that it is a problem so I wrote what I did hypothesizing on that assumption.
If you really want to know my opinion about Foldable instances, we can discuss in a different thread. I'm quite cognizant of the arguments pro and contra the FTP proposal.
I participated in this conversation in the spirit of nudging it back to X--the problem--rather than letting it fester on a fixation on Y--the attempted solution because as the record demonstrates, we have a classic XY problem on our hands: http://xyproblem.info/
I started talking about this as different reasons I could think of why you would want to be explicit about what instances you're using (this is what I understood from
Why would you want to do that?
)Georgi Lyubenov // googleson78 said:
The "you" in the question was specific. It is a "you with whatever problem you are facing hic et nunc" rather than a hypothetical "you" in all possible worlds.