提前为初学者问题道歉,但我一直在努力寻找有用的信息。我正在努力学习“了解你的Haskell for Great Good”,并且我正在尝试理解派生关键字,这似乎是Java的工具,但据说由于类别理论的东西或类似的东西,它具有很酷的自动代码生成。我声明了像
这样的2向量的数据结构data R2 = R2 {x :: Double, y :: Double} deriving (Show)
然后我可以用它来做像
这样的事情show (R2 1.0 2.0)
现在我想做的是矢量加法和标量乘法,比如
(2.0 * (R2 1.0 2.0)) + (R2 3.0 4.0)
但是当我尝试
时Prelude> data R2 = R2 { x :: Double, y :: Double} deriving (Num,Show)
<interactive>:3:52:
Can't make a derived instance of `Num R2':
`Num' is not a derivable class
In the data declaration for `R2'
所以编译器想出了如何显示原始类型的笛卡尔积,但是加法太难了?也许Num不是正确的派生类型?有多少人可以期望派生一个类型类并在没有额外工作的情况下获得工作代码,比如我不必编写自己的show函数?
非常感谢,
约翰
答案 0 :(得分:6)
尝试理解派生关键字,这似乎是Java的实现,但据说有很酷的自动代码生成
instance
有点像implements
,因为您声明类型是类型类的实例,然后编写实现。 deriving
是关于这些实现的很酷的自动生成(尽管它确实包含instance
)。
有多少人可以期望派生一个类型类并在没有额外工作的情况下获得工作代码,比如我不必编写自己的show函数?
阿列克谢·罗曼诺夫的答案涵盖了哪些课程deriving
有效。还有另一种自动生成实例的方法:使用泛型。从鸟的视角来看,它的工作方式如下:您描述了一个实例对于泛型类型应该是什么样子,然后,对于您想要拥有实例的任何类型,派生Generic
并添加一个空(即没有实现,因为它们将自动生成)instance
声明。有些图书馆如aeson
和binary
offer generic instances ready to use,您当然可以roll your own为您的班级。
答案 1 :(得分:5)
请参阅https://downloads.haskell.org/~ghc/7.10.2/docs/html/users_guide/deriving.html:
在Haskell 98中,可能出现在derinding子句中的唯一类是标准类Eq,Ord,Enum,Ix,Bounded,Read和Show。
GHC还允许为Generic
声明派生Functor
,Data
,Typeable
,Foldable
,Traversable
和data
,和newtype
声明的任何类(在启用链接页面中列出的相关扩展之后)。
答案 2 :(得分:5)
这是您无法获得Num类
的一个原因$this->upload->initialize($config);
两者都是真正的程序员可能想要定义的合理实例。对于包含两个data Vector = Vector Int Int
instance Num Vector where
Vector a b + Vector c d = Vector (a + c) (b + d)
Vector a b * Vector c d = Vector (a * c) (b * d)
data Complex = Complex Int Int
instance Num Complex where
Complex a b + Complex c d = Complex (a + c) (b + d)
Complex a b * Complex c d = Complex (a * c - b * d) (a * d + b * c)
字段的给定数据定义,Int
子句应选择哪个实例?
答案 3 :(得分:4)
Haskell Report 2010(描述Haskell语言的文档以及所有实现应遵循的文档)定义了派生类C
的条件,如下所示:
- C是
Eq
,Ord
,Enum
,Bounded
,Show
或Read
之一。- 有一个上下文
cx′
,cx′ ⇒ C tij
适用于每种成分类型tij
。- 如果
C
是Bounded
,则类型必须是枚举(所有构造函数必须是nullary)或者只有一个构造函数。- 如果
C
为Enum
,则类型必须为枚举。- 程序中的其他位置必须没有明确的实例声明,使
T u1 … uk
成为C
的实例。- 如果数据声明没有构造函数(即当n = 0时),则不会派生任何类。
醇>
此外,在报告的后面,据说derive Data.Ix
instances也可以。
要了解特定实例是如何准确派生的(例如,派生的Show
实例输出是什么?),请阅读报告中的section about it。该部分仅给出了满足上述条件的情况的实现。这就是为什么无法导出Num
个实例的原因:它没有指定该实例应该做什么!
GHC还提供了一些扩展,允许派生更多的类。
这些扩展不是标准Haskell的一部分,因此必须明确启用它们。例如,如果启用了GenericNewtypeDeriving
,则可以编写以下内容:
newtype MyInt = MyInt Int deriving (Num)
-- By GenericNewtypeDeriving, GHC will just "copy" the instance
-- for the base type of the newtype, in this case, it'll use the `Num Int` instance.
您可以在GHC user guide
中了解这些扩展程序答案 4 :(得分:0)
可悲的是,导出仅适用于少数几个类,其中必要的代码硬编码到编译器中。您可以自己为任何类编写实例,但只有这一小部分可以自动派生 。