[Haskell-cafe] can't figure out a type

John Lato jwlato at gmail.com
Thu Feb 12 18:08:02 EST 2009


Hi Job, thanks for replying.

Thanks for explaining this.  I never really thought about the
implications of kinds on type classes, and it's all much more clear
now.

The first version, with only one parameter, almost works, except that
some instances (e.g. uvector, storablevector) have further class
restrictions on the element types.  I believe these are impossible to
express without the element parameter included in the Chunkable class.
 This was  a big disappointment, because otherwise it would be
possible in Haskell98.

This is also a problem with the map implementation.  Since the
typeclass restriction exists for both el and el', I don't see how it's
possible to type cMap without including el' in the class.  I don't
want to do that, so I guess the map function will just need to be
provided outside the class instance.  It does turn out that I don't
need either fundeps or type families at least.

Thanks to everyone who replied; it really helped me clarify my
thoughts on this implementation.

Cheers,
John Lato

On Wed, Feb 11, 2009 at 8:28 PM, Job Vranish <jvranish at gmail.com> wrote:
> I think what you probably want is something like this:
>
> class Chunckable c where
>  cLength :: c el -> Int
>  cHead :: c el -> Maybe el
>  cMap :: (a -> b) -> c a -> c b
>
> instance Chunckable [] where
>  cLength [] = 0
>  cLength (x:xs) = 1 + cLength xs
>
>  cHead [] = Nothing
>  cHead (x:xs) = Just x
>
>  cMap = map
>
> a = [4, 7, 3, 8]
> test1 = cLength a
> test2 = cHead a
> test3 = cMap (Just) a
>
>
> The class does not actually need the second type parameter.
> You can actually use all sorts of extra type variables in the type
> signatures in class declarations as long as all your instances are
> polymorphic across those types (not sure if that's the precise
> terminology). Basically, as long as cLength, cHead and cMap do the
> same thing regardless of what el is, then you don't need to have el as
> a type parameter to the class.
>
> Now if you _do_ want to have cLength, etc do something else depending
> el, then things get more complicated. Maybe something like this:
>
> class Chunckable2 c el where
>  cLength2 :: c el -> Int
>  cHead2 :: c el -> Maybe el
>  cMap2 :: (Chunckable2 c el') => (el -> el') -> c el -> c el'
>
> instance Chunckable2 [] Int where
>  cLength2 [] = 0
>  cLength2 (x:xs) = 1 + cLength xs
>
>  cHead2 [] = Nothing
>  cHead2 (x:xs) = Just x
>
>  cMap2 = map
>
> instance Chunckable2 [] Float where
>  cLength2 [] = 0
>  cLength2 (x:xs) = 1 + cLength xs
>
>  cHead2 [] = Nothing
>  cHead2 (x:xs) = Just x
>
>  cMap2 f xs = []
>
> test4 = cMap2 (fromIntegral) (a::[Int]) :: [Float]
> test5 = cMap2 (id) ([3.0, 4.0, 1.0]::[Float])  :: [Float]
>
> Note that if you want things to work like this, functional
> dependencies wont help you out (as they don't make sense in this case)
>
>
>
> On Wed, Feb 11, 2009 at 12:34 PM, John Lato <jwlato at gmail.com> wrote:
>> Hi Job,
>>
>> Thanks for answering.  What I'm trying to do is probably very simple,
>> and I think the biggest problem is that I don't fully understand kinds
>> yet.
>>
>> Here's an example instance:
>>
>> instance Chunkable [a] a where
>>  cmap = map
>>  --etc.
>>
>> In the class I wrote, c has kind * (e.g. [a]), but then I don't see
>> how to write a suitable map function.  For that, I would want c to
>> have kind * -> *.  Unfortunately then I don't know to write the
>> others.
>>
>> Would I have to do something with c having kind (* -> *) ?
>>
>> class Chunkable2 c el where
>>   cLength :: c el -> Int
>>   cHead :: c el -> Maybe el
>>   cMap :: (el -> el') -> c el -> c el'
>>
>> Sincerely,
>> John
>>
>> On Wed, Feb 11, 2009 at 5:12 PM, Job Vranish <jvranish at gmail.com> wrote:
>>> What do you mean by parameterized over a different type?
>>> will c have a kind of * -> * ? I don't think it has to be for what you
>>> want to work, but the idea of "same instance" will go out the window.
>>>
>>> Do you have a small usage example?
>>>
>>>
>>> On Wed, Feb 11, 2009 at 11:52 AM, John Lato <jwlato at gmail.com> wrote:
>>>> Hello,
>>>>
>>>> I'm working on some code like the following:
>>>>
>>>>> class Chunkable c el | c -> el where
>>>>>   cLength :: c -> Int
>>>>>   cHead :: c -> Maybe el
>>>>
>>>> I want to be able to map over this type, like this:
>>>>
>>>>>  cMap :: Chunkable c' el' => (el -> el') -> c -> c'
>>>>
>>>> but this isn't quite right.  c' shouldn't be any instance of
>>>> Chunkable, it should be the same instance except parameterized over a
>>>> different type.  Another approach would be something like:
>>>>
>>>> class (Functor c) => Chunkable c el
>>>> ...
>>>>
>>>> except that's not right either.  I think c has the wrong kind to be a
>>>> Functor instance.
>>>>
>>>> I expect there's something very basic I'm missing.  Could anyone point
>>>> in the proper direction of how to do this?  Can this be expressed with
>>>> associated types, perhaps?
>>>>
>>>> Thanks,
>>>>
>>>> John Lato
>>>> _______________________________________________
>>>> Haskell-Cafe mailing list
>>>> Haskell-Cafe at haskell.org
>>>> http://www.haskell.org/mailman/listinfo/haskell-cafe
>>>>
>>>
>>
>


More information about the Haskell-Cafe mailing list