使用基于整数Haskell的newtypes执行代数

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)

关于这里的继承是如何工作的,我找不到清楚明确的解释.任何和所有的帮助将不胜感激.

Wil*_*sem 8

好吧Haskell不能加两个Money,因为你从未指定过如何做到这一点.为了加起来两个a,as应该实现Num类型类.事实上newtypes的经常用于指定不同类型的情况下,例如SumProduct用于定义两个不同的类群.

因此,您需要将其作为实例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 = Money
Run Code Online (Sandbox Code Playgroud)

由于(/) :: Fractional a => a -> a -> aFractional类型类的成员,因此Money包装Integer对象会产生一些问题.

但是,您可以实现Integral它支持的类型类div.为此,我们需要实现RealEnum类型类.该Real类型类要求类型是实现Ord,并且由于Ord类型类要求对象是的一个实例Eq类型类,我们从而最终实现Eq,Ord,RealEnum类型类.

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 y
Run Code Online (Sandbox Code Playgroud)

GeneralizedNewtypeDeriving

正如@Alec所说,我们可以使用名为GHC的扩展名-XGeneralizedNewtypeDeriving.

上面的推导在这里非常"无聊"我们每次"解包"数据构造函数,执行一些操作,并"重新"它们(在某些情况下,无需解包或重新打包).特别是因为newtype实际上在运行时并不存在(这是让Haskell以不同方式处理数据,但数据构造函数将被"优化掉")的一种方式,它没有多大意义.

如果我们编译:

ghc -XGeneralizedNewtypeDeriving file.hs
Run 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编译器本身并不具备(当然它们可以具有此功能)支持这一功能.

  • 可能值得一提的是'GeneralizedNewtypeDeriving` ... :) (2认同)