使用基于整数的新类型执行代数 Haskell
Performing algebra with newtypes based on integers Haskell
我在执行简单的加法、减法时遇到了一些麻烦 -- 任何类型的 Haskells newtype 代数。
我的定义是(包含显示以便我可以将它们打印到控制台):
newtype Money = Money Integer deriving Show
我想做的基本上是:
Money 15 + Money 5 = Money 20
Money 15 - Money 5 = Money 10
Money 15 / Money 5 = Money 3
依此类推,但我得到
m = Money 15
n = Money 5
Main>> m-n
ERROR - Cannot infer instance
*** Instance : Num Money
*** Expression : m - n
对于这里的继承是如何工作的,我找不到一个清晰而简洁的解释。任何帮助将不胜感激。
好吧 Haskell 不能将两个 Money
相加,因为您从未指定如何做。为了将两个 a
相加,a
应该实现 Num
类型类。事实上newtype
经常被用来指定不同的类型实例,例如Sum
and 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 = Money
由于 (/) :: Fractional a => a -> a -> a
是 Fractional
类型类的成员,这会带来一些问题,因为您的 Money
包装了一个 Integer
对象。
但是您可以实现 Integral
typeclass such that it supports div
. In order to do this, we however need to implement the Real
and Enum
typeclass. The Real
typeclass requires the type to be implement the Ord
, and since the Ord
typeclass requires the object to be an instance of the 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 y
GeneralizedNewtypeDeriving
如 we can use a GHC extension named -XGeneralizedNewtypeDeriving
.
上面的推导相当 "boring" 这里我们每次 "unwrap" 数据构造函数,执行一些操作,然后 "rewrap" 它们(在某些情况下要么解包要么不需要重新包装)。特别是因为 newtype
在运行时实际上并不存在(这更像是一种让 Haskell 区别对待数据的方式,但数据构造函数将是 "optimized away"),这没有多大意义.
如果我们编译:
ghc <b>-XGeneralizedNewtypeDeriving</b> file.hs
我们可以将 Money
类型声明为:
newtype Money = Money Integer deriving (Show, <b>Num</b>, Enum, Eq, Ord, <b>Real, Integral</b>)
和Haskell将为我们进行上述推导。据我所知,这是 GHC 的一项功能,因此其他 Haskell 编译器本身 (他们当然可以拥有此功能)不支持此功能。
您错过了如何将您的钱加在一起的实例,线索在错误 Instance : Num Money
。
因此,对于 Haskell 中的加法,Num
键入需要将两件事加在一起的内容,只要您处理的是数字,那么让我们在 [= 上创建 Num
的实例14=]:
newtype Money =
Money Integer deriving Show
instance Num Money where
Money a + Money b = Money $ a + b
-- Money 1 + Money 2 == Money 3
请注意,它 returns Money
会让您研究如何从类型中获取数字 :)
我在执行简单的加法、减法时遇到了一些麻烦 -- 任何类型的 Haskells newtype 代数。
我的定义是(包含显示以便我可以将它们打印到控制台):
newtype Money = Money Integer deriving Show
我想做的基本上是:
Money 15 + Money 5 = Money 20
Money 15 - Money 5 = Money 10
Money 15 / Money 5 = Money 3
依此类推,但我得到
m = Money 15
n = Money 5
Main>> m-n
ERROR - Cannot infer instance
*** Instance : Num Money
*** Expression : m - n
对于这里的继承是如何工作的,我找不到一个清晰而简洁的解释。任何帮助将不胜感激。
好吧 Haskell 不能将两个 Money
相加,因为您从未指定如何做。为了将两个 a
相加,a
应该实现 Num
类型类。事实上newtype
经常被用来指定不同的类型实例,例如Sum
and 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 = Money
由于 (/) :: Fractional a => a -> a -> a
是 Fractional
类型类的成员,这会带来一些问题,因为您的 Money
包装了一个 Integer
对象。
但是您可以实现 Integral
typeclass such that it supports div
. In order to do this, we however need to implement the Real
and Enum
typeclass. The Real
typeclass requires the type to be implement the Ord
, and since the Ord
typeclass requires the object to be an instance of the 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 y
GeneralizedNewtypeDeriving
如-XGeneralizedNewtypeDeriving
.
上面的推导相当 "boring" 这里我们每次 "unwrap" 数据构造函数,执行一些操作,然后 "rewrap" 它们(在某些情况下要么解包要么不需要重新包装)。特别是因为 newtype
在运行时实际上并不存在(这更像是一种让 Haskell 区别对待数据的方式,但数据构造函数将是 "optimized away"),这没有多大意义.
如果我们编译:
ghc <b>-XGeneralizedNewtypeDeriving</b> file.hs
我们可以将 Money
类型声明为:
newtype Money = Money Integer deriving (Show, <b>Num</b>, Enum, Eq, Ord, <b>Real, Integral</b>)
和Haskell将为我们进行上述推导。据我所知,这是 GHC 的一项功能,因此其他 Haskell 编译器本身 (他们当然可以拥有此功能)不支持此功能。
您错过了如何将您的钱加在一起的实例,线索在错误 Instance : Num Money
。
因此,对于 Haskell 中的加法,Num
键入需要将两件事加在一起的内容,只要您处理的是数字,那么让我们在 [= 上创建 Num
的实例14=]:
newtype Money =
Money Integer deriving Show
instance Num Money where
Money a + Money b = Money $ a + b
-- Money 1 + Money 2 == Money 3
请注意,它 returns Money
会让您研究如何从类型中获取数字 :)