RFC: Add HasCallStack constraint to partial Data.List functions.

Julian Ospald hasufell at posteo.de
Wed Jun 9 07:31:17 UTC 2021


Yeah, I think a typeclass to express partiality is a sloppy technique. I'm not even sure everyone agrees on what 'partial' means: if my function throws an IO error on relative FilePaths, is it partial? Is all IO partial?

Haskell is definitely not a total language and I doubt it will be. I also don't think that it's an interesting goal. It requires a considerable shift in language design.

HasCallstack sounds like a pragmatic solution, but you could as well create an alternative prelude that adds it everywhere you want and then avoid implicit prelude. That won't help you with unsound dependencies, that don't use it, but it's opt-in, which seems more reasonable given that it's obviously a somewhat controversial change.

I'd expect the nay-sayers here, however, to be a driving force in a better GHC based solution. Otherwise, the next time this comes up people will say "you had time enough".

On June 8, 2021 6:10:52 PM UTC, Oliver Charles <ollie at ocharles.org.uk> wrote:
>
>
>On Tue, 8 Jun 2021, at 6:36 PM, Richard Eisenberg wrote:
>> I've been very much of two minds in this debate: On the one hand,
>having these constraints is very practically useful. On the other, what
>we're doing here is very un-Haskellish, in that we're letting
>operational concerns leak into a declarative property (a function's
>type). The reason we're doing this is another un-Haskellish thing --
>partiality -- but that ship has sailed.
>> 
>> So, may I propose a slightly different way forward?
>> 
>> Instead of adding a HasCallStack constraint on these functions, add
>an IsPartial constraint. For example:
>> 
>> > head :: IsPartial => [a] -> a
>> 
>> This is slightly awkward, still, because IsPartial is a
>class-constraint-like-thing, but it has no parameter. But it has a few
>very nice properties:
>> * IsPartial is declarative: it describes a property of the function
>without worrying about its operation.
>> * If we think about the way constraints propagate, IsPartial has the
>right semantics: the caller of a partial function would itself become
>partial.
>
>I don't think this is true.
>
>Take:
>
>foo :: Int -> Bool
>foo _ = head [True]
>
>Clearly foo is total - it is defined for all of its inputs. That it
>uses a partial function in its body isn't observable. So it's a shame
>that IsPartial leaks out.
>
>I guess here you'd have me say
>
>foo _ = partialityIsOk $ head [True]
>
>?
>
>Ollie
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/libraries/attachments/20210609/a1b9e383/attachment.html>


More information about the Libraries mailing list