3

I have a newtype X, which is basically a list of Ints. I use ClassyPrelude instead of the standard Prelude and want to derive the IsSequence class. This makes it necessary to also derive lots of other classes.

The language extension GeneralizedNewtypeDeriving should allow this (here used together with the DerivingStrategies extension). I want:

newtype X = X [Int] deriving newtype (MonoFunctor, MonoFoldable, MonoTraversable, Monoid, GrowingAppend, SemiSequence, MonoPointed, IsSequence)

full file:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleContexts #-}

module Test where

import ClassyPrelude

newtype X = X [Int] deriving newtype (MonoFunctor, MonoFoldable, MonoTraversable, Monoid, GrowingAppend, SemiSequence, MonoPointed, IsSequence)

type instance Element X = Int

(all other language extensions seem to be important)

However, this produces lots of error messages for MonoTraversable and IsSequence:

/path/to/file/Test.hs:13:48: error:
    • Couldn't match representation of type ‘m [Int]’
                               with that of ‘m X’
        arising from the coercion of the method ‘omapM’
          from type ‘forall (m :: * -> *).
                     Applicative m =>
                     (Element [Int] -> m (Element [Int])) -> [Int] -> m [Int]’
            to type ‘forall (m :: * -> *).
                     Applicative m =>
                     (Element X -> m (Element X)) -> X -> m X’
      NB: We cannot know what roles the parameters to ‘m’ have;
        we must assume that the role is nominal
    • When deriving the instance for (MonoTraversable X)
   |
13 |   deriving newtype (MonoFunctor, MonoFoldable, MonoTraversable, Monoid, GrowingAppend, SemiSequence, MonoPointed, IsSequence)
   |                                                ^^^^^^^^^^^^^^^

/path/to/file/Test.hs:13:48: error:
    • Couldn't match representation of type ‘f [Int]’
                               with that of ‘f X’
        arising from the coercion of the method ‘otraverse’
          from type ‘forall (f :: * -> *).
                     Applicative f =>
                     (Element [Int] -> f (Element [Int])) -> [Int] -> f [Int]’
            to type ‘forall (f :: * -> *).
                     Applicative f =>
                     (Element X -> f (Element X)) -> X -> f X’
      NB: We cannot know what roles the parameters to ‘f’ have;
        we must assume that the role is nominal
    • When deriving the instance for (MonoTraversable X)
   |
13 |   deriving newtype (MonoFunctor, MonoFoldable, MonoTraversable, Monoid, GrowingAppend, SemiSequence, MonoPointed, IsSequence)
   |                                                ^^^^^^^^^^^^^^^

/path/to/file/Test.hs:13:115: error:
    • Couldn't match type ‘[Int]’ with ‘X’
        arising from the coercion of the method ‘initMay’
          from type ‘IsSequence [Int] => [Int] -> Maybe [Int]’
            to type ‘IsSequence X => X -> Maybe X’
    • When deriving the instance for (IsSequence X)
   |
13 |   deriving newtype (MonoFunctor, MonoFoldable, MonoTraversable, Monoid, GrowingAppend, SemiSequence, MonoPointed, IsSequence)
   |                                                                                                                   ^^^^^^^^^^

/path/to/file/Test.hs:13:115: error:
    • Couldn't match representation of type ‘m [Int]’
                               with that of ‘m X’
        arising from the coercion of the method ‘replicateM’
          from type ‘forall (m :: * -> *).
                     Monad m =>
                     Index [Int] -> m (Element [Int]) -> m [Int]’
            to type ‘forall (m :: * -> *).
                     Monad m =>
                     Index X -> m (Element X) -> m X’
      NB: We cannot know what roles the parameters to ‘m’ have;
        we must assume that the role is nominal
    • When deriving the instance for (IsSequence X)
   |
13 |   deriving newtype (MonoFunctor, MonoFoldable, MonoTraversable, Monoid, GrowingAppend, SemiSequence, MonoPointed, IsSequence)
   |                                                                                                                   ^^^^^^^^^^

/path/to/file/Test.hs:13:115: error:
    • Couldn't match representation of type ‘m [Int]’
                               with that of ‘m X’
        arising from the coercion of the method ‘filterM’
          from type ‘forall (m :: * -> *).
                     Monad m =>
                     (Element [Int] -> m Bool) -> [Int] -> m [Int]’
            to type ‘forall (m :: * -> *).
                     Monad m =>
                     (Element X -> m Bool) -> X -> m X’
      NB: We cannot know what roles the parameters to ‘m’ have;
        we must assume that the role is nominal
    • When deriving the instance for (IsSequence X)
   |
13 |   deriving newtype (MonoFunctor, MonoFoldable, MonoTraversable, Monoid, GrowingAppend, SemiSequence, MonoPointed, IsSequence)
   |                                              

which I cannot read (maybe it has to do with default signatures?, no idea...). Leaving out the 2 classes from the deriving clause makes the code compile.

Question: how to derive IsSequence in this case?

For several reasons, a type-alias is not possible for my use-case but I want to use the functions provided by these classes. If the deriving is not possible, it would be necessary to implement the class-methods myself.

Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
  • In the future, please include your code and the error in the question itself (not off-site). Making the question self-contained makes it more likely to be useful to future visitors. (I have moved your off-site resources into the question itself for you this time.) – Daniel Wagner Apr 11 '18 at 14:01
  • This is a limitation of the role system - it has no way to express that `m A` is coercible to `m B` if `A` is coercible to `B`, for a type variable `m`. I'm not sure if there is a workaround for these specific classes (alternate deriving mechanism maybe?) – user2407038 Apr 11 '18 at 14:25
  • 2
    @user2407038 Ryan Scott has written about the proposed `QuantifiedConstraints` feature as a possible solution for this https://ryanglscott.github.io/2018/03/04/how-quantifiedconstraints-can-let-us-put-join-back-in-monad/ – Benjamin Hodgson Apr 11 '18 at 14:26
  • What is the role system? Why is it not possible to automatically? The manual implementation for IsSequence would be simply by delegating everything to the contained list: `fromList = X . fromList`, `filter f (X s) = X $ filter s` and so on. Why is this not possible to do automatically? – Samuel Pilz Apr 11 '18 at 16:21
  • @SamuelPilz Read the article I linked above, it answers your questions in detail – Benjamin Hodgson Apr 11 '18 at 16:32
  • See the [user guide](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#roles) for an explanation of what roles are. It isn't possible because it's a limitation of the system; this means that in theory it is possible, but in practice it has not yet been implemented. – user2407038 Apr 11 '18 at 21:14

0 Answers0