Mat*_*ats 4 haskell algebra newtype
我在执行简单的加法,减法时遇到了一些麻烦 - 任何类型的代数都与Haskells newtype有关.
我的定义是(显示包含所以我可以将它们打印到控制台):
newtype Money = Money Integer deriving Show
Run Code Online (Sandbox Code Playgroud)
我想要做的基本上是:
Money 15 + Money 5 = Money 20
Money 15 - Money 5 = Money 10
Money 15 / Money 5 = Money 3
Run Code Online (Sandbox Code Playgroud)
等等,但我得到了
m = Money 15
n = Money 5
Main>> m-n
ERROR - Cannot infer instance
*** Instance : Num Money
*** Expression : m - n
Run Code Online (Sandbox Code Playgroud)
关于这里的继承是如何工作的,我找不到清楚明确的解释.任何和所有的帮助将不胜感激.
好吧Haskell不能加两个Money,因为你从未指定过如何做到这一点.为了加起来两个a,as应该实现Num类型类.事实上newtypes的经常用于指定不同类型的情况下,例如Sum和Product用于定义两个不同的类群.
因此,您需要将其作为实例Num,因此您必须定义一个实例,如:
instance Num Money where
Money a + Money b = Money (a+b)
Money a - Money b = Money (a-b)
Money a * Money b = Money (a*b)
abs (Money a) = Money (abs a)
signum (Money a) = Money (signum a)
fromInteger = MoneyRun Code Online (Sandbox Code Playgroud)
由于(/) :: Fractional a => a -> a -> a是Fractional类型类的成员,因此Money包装Integer对象会产生一些问题.
但是,您可以实现Integral它支持的类型类div.为此,我们需要实现Real和Enum类型类.该Real类型类要求类型是实现Ord,并且由于Ord类型类要求对象是的一个实例Eq类型类,我们从而最终实现Eq,Ord,Real和Enum类型类.
instance Eq Money where
Money x == Money y = x == y
instance Ord Money where
compare (Money x) (Money y) = compare x y
instance Real Money where
toRational (Money x) = toRational x
instance Enum Money where
fromEnum (Money x) = fromEnum x
toEnum = Money . toEnum
instance Integral Money where
toInteger (Money x) = x
quotRem (Money x) (Money y) = (Money q, Money r)
where (q, r) = quotRem x yRun Code Online (Sandbox Code Playgroud)
GeneralizedNewtypeDeriving正如@Alec所说,我们可以使用名为GHC的扩展名-XGeneralizedNewtypeDeriving.
上面的推导在这里非常"无聊"我们每次"解包"数据构造函数,执行一些操作,并"重新"它们(在某些情况下,无需解包或重新打包).特别是因为newtype实际上在运行时并不存在(这是让Haskell以不同方式处理数据,但数据构造函数将被"优化掉")的一种方式,它没有多大意义.
如果我们编译:
ghc -XGeneralizedNewtypeDeriving file.hsRun Code Online (Sandbox Code Playgroud)
我们可以将Money类型声明为:
newtype Money = Money Integer deriving (Show, Num, Enum, Eq, Ord, Real, Integral)Run Code Online (Sandbox Code Playgroud)
和Haskell将为我们执行上述推导.据我所知,这是一个GHC功能,因此其他Haskell编译器本身并不具备(当然它们可以具有此功能)支持这一功能.