Haskell冒险继续。
目前,我正在尝试在Haskell中构建我自己的Fraction类型,以满足我的需求。 它基本上只是一个类型Fraction {n :: Int,d :: Int}和许多函数,其中大多数都是x->分数
所以我现在要做的就是确保分数只能是正数,或者分子中是负数,分母中是正数,通过将任何其他可能性转换为其中一种。
--e.g
(Fraction (3 (-5))->Fraction (-3) 5
--and
(Fraction (-3) (-5))->Fraction 3 5
每次某些函数x-> Fraction都会返回其中一个。 我认为必须有一种更聪明的方法来做到这一点,而不是逐个修改每个x->分数函数。我的猜测已经在分数类型定义中了。
我没有那么长时间的编程,所以我可能不会完全胜过技术术语。
感谢阅读,谢谢你的回答
修改
我决定使用Eq Instance解决方案,并且添加了如果Signum分子* Signum分母不匹配,则返回false给警卫。无论如何我不得不分数。和书房。在比较之前用HCD
我最初要求的智能构造函数也将用于我同时制作的Matrix nXn(Q)模块中:)
很棒的答案。感谢。
答案 0 :(得分:8)
您可以使用smart constructors来确保对类型的这些约束,并通过不导出它们来隐藏数据构造函数。智能构造函数本质上是一种函数,可以保证类型系统无法实现的约束。
答案 1 :(得分:5)
我实际上会让它们像它们一样继续计算,但如果你真的想要:将Fraction
的定义放在一个单独的模块中,不要导出它的构造函数。而是导出像makeFraction :: Int -> Int -> Fraction
这样的函数来处理“转换”。
现在,模块外的每个人都只能按照你想要的方式构建分数。
答案 2 :(得分:3)
我认为一个想法就是保持内部表现形式。也就是说,在你对你的数字进行操作之前,你不会关心你的分子和分母的实际符号。
例如,如果你想比较两个分数,这可以通过派生Eq类的实例来完成(当然这涉及到对type classes有一点了解),你可以简单地检查一下
signum d1 * signum n1 == signum d2 * signum n2
除了检查值。
请注意,在处理分数时还需要检查其他方面。例如:
Fraction 6 2 == Fraction 3 1
替代方案将涉及添加单独的符号字段并使用Natural数字作为分子和分母。
答案 3 :(得分:3)
如果你真的使用的是Int
而不是Integer
,那么类型系统(和实现)可以解决这个特殊问题而不需要任何技巧或隐藏。类型Word
表示正整数机器:
Prelude Data.Word> [minBound,maxBound] :: [Word]
[0,18446744073709551615]
Prelude Data.Word> [minBound,maxBound] :: [Int]
[-9223372036854775808,9223372036854775807]
所以你可以写:
import Data.Word
data Fraction = Int :/ Word deriving Show
fi = fromIntegral
instance Eq Fraction where
(i :/ w) == (j :/ v) = i * fi v == j * fi w
instance Num Fraction where
fromInteger n = fromInteger n :/ 1
(i :/ w) * (j :/ v) = (i * j) :/ (w * v)
(i :/ w) + (j :/ v) = i * fi v + j * fi w :/ w * v
(i :/ w) - (j :/ v) = (i :/ w) + (negate j :/ v)
negate (i :/ w) = (negate i:/ w)
abs (i :/ w) = (abs i :/ w)
signum (i :/ w) = (signum i :/ 1)
您将通过严格和解包获得更多类似于机器号的行为:
data Fraction = {-#UNPACK#-} !Int :/ {-#UNPACK#-} !Word deriving Show