0

I would like to derive a class with a constant and some trivial operations:

class  Zeros z where
    zero :: z
    isZero  :: Eq z =>  z -> Bool
    isZero z = zero == z

and in another module:

{-# LANGUAGE DeriveGeneric, DeriveAnyClass
    , GeneralizedNewtypeDeriving #-}
module Lib.DerivingExampleDerive
    where
import Data.Text
import Lib.DerivingExample
import GHC.Generics

newtype Basis1 = Basis1 Text deriving (Show, Read, Eq, Ord, Generic, Zeros)

GHC 8.2.2 produces the error:

/home/frank/Workspace8/testSome/Lib/DerivingExampleDerive.hs:26:70: warning:
    • Both DeriveAnyClass and GeneralizedNewtypeDeriving are enabled
      Defaulting to the DeriveAnyClass strategy for instantiating Zeros
    • In the newtype declaration for ‘Basis1’
   |         
26 | newtype Basis1 = Basis1 Text deriving (Show, Read, Eq, Ord, Generic, Zeros)
   |                                                                      ^^^^^

/home/frank/Workspace8/testSome/Lib/DerivingExampleDerive.hs:26:70: warning: [-Wmissing-methods]
    • No explicit implementation for
        ‘zero’
    • In the instance declaration for ‘Zeros Basis1’
   |         
26 | newtype Basis1 = Basis1 Text deriving (Show, Read, Eq, Ord, Generic, Zeros)
   |                                                                      ^^^^^

I understand the first message (considering Ryan Scott's blog post on deriving strategies but not the second.

Should I conclude that the deriving mechanism in Haskell cannot derive constants? I have given

instance Zeros Text where zero = (""::Text)

and the derivation for

instance Zeros Basis1 where zero = Basis1 zero  

should be resulting from the strategy of DeriveAnyClass but is not.

dfeuer
  • 48,079
  • 5
  • 63
  • 167
user855443
  • 2,596
  • 3
  • 25
  • 37
  • How should Haskell know what the `zero` element should be? But indeed, only for some specific cases, Haskell can perform automatic derivations. – Willem Van Onsem Mar 13 '18 at 10:19
  • Could you point me to the list of the `specific cases` ? what is different in the expected derived instance for Basis1 compared to deriving, e.g., show? The newtype constructor is added.. - Would it be difficutl to implement in GHC to derive for constans? – user855443 Mar 13 '18 at 10:49
  • see https://stackoverflow.com/a/3864746/67579 – Willem Van Onsem Mar 13 '18 at 10:52
  • and you do not really provide a way to derive what `zero` is, a conservative compiler can thus not simply make a lucky guess. – Willem Van Onsem Mar 13 '18 at 10:54
  • Thank you for your patience. I must miss something: An instance for Text is given and I assume that the derivation for the newtype `Basis1 Text` should use it automatically - the same it would for `show`. In https://downloads.haskell.org/~ghc/7.4.2/docs/html/users_guide/generic-programming.html mechanism for deriving constants are mentioned; should I use the mechanism described there? – user855443 Mar 13 '18 at 11:44

2 Answers2

3

GeneralizedNewtypeDeriving will write the instance you propose, but DeriveAnyClass will write this instance:

instance Zeros Text => Zeros Basis1

N.B. there are no method definitions! For that to work, you need to give a default implementation for every method; usually this is done with generics or a similar generic programming toolkit.

Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
  • Thank you for the pointer to GHC.Generics, which I read but do not see how to apply it here. I have (naively) coded: class Zeros z where zero :: z default zero :: (Generic z, Gzero (Rep z)) => z zero = gzero (from z) class Gzero f where gzero :: f a -> a instance Gzero U1 where gzero U1 = a but got errors on both lines with gzero. I tried to derive Monoid from Data.Monoid, but cannot derive it for a data type (but for newtypes). Can automatic derivatin of Zeros not be done or can my code be improved? if not, why? – user855443 Mar 13 '18 at 22:22
  • @user855443 Please open a fresh question with the details of your attempt (including an [MCVE](https://stackoverflow.com/help/mcve)) and the exact error message it produces. – Daniel Wagner Mar 13 '18 at 22:26
  • Thank you for the advice: the new question is https://stackoverflow.com/questions/49276305/how-to-write-an-instance-for-generic-to-derive-a-function-like-zeroa-i-e-a-c – user855443 Mar 14 '18 at 11:16
2

You pointed to Ryan's blog post that explains a fix. Why don't you use it? Add DerivingStrategies and then use deriving newtype Zeros.

dfeuer
  • 48,079
  • 5
  • 63
  • 167
  • I use this solution, but it is limited to types defined as newtype and does not work for `data X = X .. `. where I think I can only use the deriving strategy `anyclass` which does not produce an instance for the function `zero`. – user855443 Mar 14 '18 at 10:24
  • @user855443, yes, but your question asked about `newtype`. Was that unintentional? – dfeuer Mar 14 '18 at 13:24
  • I learned only from the advice i received that newtype deriving is only applicable to newtype definitions and that for data definitions i need anyclass. therefore Ryan's very useful blog post solved most of my problem and left the case where anyclass is required open. The question was posed with incomplete understanding... – user855443 Mar 14 '18 at 16:04