【问题标题】:Deriving a class with a single constant派生具有单个常量的类
【发布时间】:2018-03-13 10:12:02
【问题描述】:

我想派生一个具有常量和一些琐碎操作的类:

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

在另一个模块中:

{-# 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 产生错误:

/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)
   |                                                                      ^^^^^

我理解第一条消息(考虑Ryan Scott's blog post on deriving strategies,但不是第二条。

我是否应该得出结论,Haskell 中的派生机制不能派生常量?我给了

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

以及

的推导
instance Zeros Basis1 where zero = Basis1 zero  

应该是DeriveAnyClass的策略导致的,但不是。

【问题讨论】:

  • Haskell 应该如何知道zero 元素应该是什么?但事实上,只有在某些特定情况下,Haskell 才能执行自动推导。
  • 您能指出specific cases 的列表吗?与派生(例如,显示)相比,Basis1 的预期派生实例有什么不同?添加了新类型构造函数.. - 在 GHC 中实现为常量派生会很困难吗?
  • 而且您并没有真正提供一种方法来推导 zero 是什么,因此保守的编译器不能简单地做出幸运的猜测。
  • 感谢您的耐心等待。我必须错过一些东西:给出了 Text 的一个实例,我假设新类型 Basis1 Text 的派生应该自动使用它 - 与 show 相同。在downloads.haskell.org/~ghc/7.4.2/docs/html/users_guide/… 中提到了派生常量的机制;我应该使用那里描述的机制吗?

标签: haskell


【解决方案1】:

GeneralizedNewtypeDeriving 会写出你提议的实例,但DeriveAnyClass 会写出这个实例:

instance Zeros Text => Zeros Basis1

注意没有方法定义!为此,您需要为每个方法提供默认实现;通常这是使用generics 或类似的通用编程工具包完成的。

【讨论】:

  • 感谢您提供指向 GHC.Generics 的指针,我已阅读但不知道如何在此处应用它。我(天真地)编码:class Zeros z where zero :: z default zero :: (Generic z, Gzero (Rep z)) => z zero = gzero (from z) class Gzero f where gzero :: fa -> a实例 Gzero U1 其中 gzero U1 = a 但在使用 gzero 的两行都有错误。我试图从 Data.Monoid 派生 Monoid,但无法为数据类型派生它(但对于新类型)。可以不进行 Zeros 的自动推导还是可以改进我的代码?如果不是,为什么?
  • @user855443 请打开一个新问题,提供您尝试的详细信息(包括MCVE)及其产生的确切错误消息。
  • 感谢您的建议:新问题是stackoverflow.com/questions/49276305/…
【解决方案2】:

您指出了 Ryan 的博客文章,该文章解释了修复方法。你为什么不使用它?添加DerivingStrategies,然后使用deriving newtype Zeros

【讨论】:

  • 我使用这个解决方案,但它仅限于定义为 newtype 的类型,不适用于data X = X .. 。我想我只能使用派生策略anyclass,它不会为函数zero生成实例。
  • @user855443,是的,但是您的问题是关于newtype。这是无意的吗?
  • 我只从收到的建议中了解到,新类型派生仅适用于新类型定义,而对于数据定义,我需要任何类。因此,Ryan 非常有用的博客文章解决了我的大部分问题,并保留了需要打开任何类的情况。这个问题是在不完全理解的情况下提出的......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-04
  • 2015-10-24
  • 1970-01-01
相关资源
最近更新 更多