[Haskell-cafe] DatatypeContexts / alternative
Ben Franksen
ben.franksen at online.de
Sun Feb 28 08:38:17 UTC 2021
Am 24.02.21 um 11:17 schrieb Tom Ellis:
> It is a rare problem that gets simpler by the
> addition of type classes.
I disagree that this is a rare problem. It is a pervasive problem. It
crops up almost everywhere, at least that is my personal experience. And
I think Section 2 of the "Partial Type Constructors" paper shows that my
experience is not particularly unusual.
Cheers
Ben
>> ________________________________
>> From: Haskell-Cafe <haskell-cafe-bounces at haskell.org> on behalf of Tom Ellis <tom-lists-haskell-cafe-2017 at jaguarpaw.co.uk>
>> Sent: 23 February 2021 19:27
>> To: haskell-cafe at haskell.org <haskell-cafe at haskell.org>
>> Subject: Re: [Haskell-cafe] DatatypeContexts / alternative
>>
>> This email was sent to you by someone outside the University.
>> You should only click on links or attachments if you are certain that the email is genuine and the content is safe.
>>
>> On Tue, Feb 23, 2021 at 06:37:06PM +0000, CASANOVA Juan wrote:
>>> Yes I realize that, but what I am expecting, I guess, is for the
>>> type checker to tell me (or anyone who tried to use it) that Foo (IO
>>> String) makes no sense, because Foo is always applied to something
>>> with Ord. That the very concept of the type Foo (IO String) itself
>>> does not type check.
>>>
>>> I realize the answer might be that this is impossible with current
>>> Haskell, but then a) Is there any fundamental reason why it is
>>> impossible
>>
>> Yes, there's a fundamental reason. Neither you nor the compiler can
>> possibly know when invalid Foos (i.e. those whose parameter isn't Ord)
>> are constructed inside a function polymorphic in a Functor . Let's
>> extend my example.
>>
>> mapToUnit :: Functor f => f a -> f ()
>> mapToUnit = fmap (const ()) . fmap (const getLine)
>>
>> whatShouldItDo :: Foo ()
>> whatShouldItDo = mapToUnit (Foo (Data.Map.singleton () ()))
>>
>> Do you agree that whatShouldItDo is well typed? If not, why not?
>> If so, how should it behave when evaluated? The implementation of
>> mapToUnit , combined with your Functor instance says that fromList
>> must be run on [(getLine, getLine)] . But this is impossible!
>>
>> Accepting that whatShouldItDo is well typed implies that you must
>> accept that your Functor instance for Foo cannot work. (I don't
>> believe any instance can work if it is law-abiding but I don't know of
>> a proof.)
>>
>> There is a cottage industry of trying to work around this problem.
>> See, for example [1]. I have never seen a satisfactory solution.
>>
>> Based on your posts here you are frequently running into the limits of
>> type class based programming in Haskell. If your purpose is practical
>> I strongly advise you to stay away from type classes for anything
>> non-trivial. Stick to the value level. Your life will be much
>> easier. If your purpose is research into type classes, or general
>> interest, then good luck and enjoy!
>>
>> Tom
>>
>>
>> [1] https://jeltsch.wordpress.com/2015/09/03/constrained-monads/
>>
>>
>>> ________________________________
>>> From: Haskell-Cafe <haskell-cafe-bounces at haskell.org> on behalf of Tom Ellis <tom-lists-haskell-cafe-2017 at jaguarpaw.co.uk>
>>> Sent: 23 February 2021 18:29
>>> To: haskell-cafe at haskell.org <haskell-cafe at haskell.org>
>>> Subject: Re: [Haskell-cafe] DatatypeContexts / alternative
>>>
>>> This email was sent to you by someone outside the University.
>>> You should only click on links or attachments if you are certain that the email is genuine and the content is safe.
>>>
>>> On Tue, Feb 23, 2021 at 06:14:59PM +0000, CASANOVA Juan wrote:
>>>> module DatatypeContextsExample where
>>>>
>>>> import Data.Map
>>>> import Data.Bifunctor
>>>>
>>>> data Foo t = Foo (Map t t)
>>>>
>>>> instance Functor Foo where
>>>> fmap f (Foo m) = Foo (fromList (fmap (bimap f f) (toList m)))
>>>>
>>>> This does not compile, because I am using toList and fromList, which
>>>> require (Ord t). But I cannot really have Foo be a functor in this
>>>> way without it. The thing is, every time I am going to use it, t is
>>>> actually going to be Ord. But how do I tell Haskell to have this
>>>> constraint?
>>>
>>> You say that every time you are going to use it t is actually going to
>>> be Ord, but how does the compiler know that when it comes to type
>>> check fmap? After all, somewhere else you could write
>>>
>>> fmap (const getLine) :: Foo t -> Foo (IO String)
>>>
>>> and IO String is certainly not Ord.
> _______________________________________________
> Haskell-Cafe mailing list
> To (un)subscribe, modify options or view archives go to:
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
> Only members subscribed via the mailman list are allowed to post.
>
More information about the Haskell-Cafe
mailing list