我正在尝试理解数据类型,为此,我想尝试模拟整数值。我用以下方式定义它:
data Number = Zero | One | Two | Three deriving (Eq,Ord,Show)
基本上,我希望能够对这种类型的元素进行基本的算术运算。类似于
的东西addNumber :: Number -> Number -> Number
调用addNumber One Two会给出Three作为结果。但是,我真的不确定如何正确地做到这一点。我假设通过比较Number相互之间可以做到这一点,但是为了得到任何东西,我需要能够以这个特定的顺序访问下一个数字,但我不知道你如何用给定的数据类型做到这一点。到目前为止,我正在做这样的事情:
getIntDex :: Number -> Int
getIntDex n = intDex n 0 nList
nList :: [Number]
nList = [Zero, One, Two, Three]
intDex :: Number -> Int -> [Number] -> Int
intDex e i (x:xs) = if((compare e x) == EQ)
then i
else intDex e (i+1) xs
至少将它“转换”成一个整数,所以我实际上可以用它做一些算术运算。然而,这感觉有点静态和整体错误(我可以通过开关或警卫或类似的东西更快地做到这一点。有更好的方法吗?
答案 0 :(得分:3)
我假设您希望避免使用内置算法 - 如果没有,因为您观察到可以转换为内置数字,算术运算并转换回来,但这不是很令人满意的“学习Haskell“观点。
在新数据类型上定义新函数的标准方法是使用模式匹配。例如,一个天真的问题方法是列出所有输入Number
对以及它们的总和:
add :: Number -> Number -> Number
add Zero Zero = Zero
add Zero One = One
add Zero Two = Two
add Zero Three = Three
add One Zero = One
add One One = Two
-- ...
当然,从程序员的角度来看,这看起来有点令人生畏和锅炉板。另一方面,拆分一些功能可能会减少它;例如,您可以编写一个函数来添加一个并迭代它:
addOne :: Number -> Number
addOne Zero = One
addOne One = Two
addOne Two = Three
addOne Three = Zero
add :: Number -> Number -> Number
add Zero = id
add One = addOne
add Two = addOne . addOne
add Three = addOne . addOne . addOne
当然,效率会略低一些;并且您不希望为更大数量的类型执行此操作。但它需要更少的手指打字。 (无论如何,对于较大数字类型,你可能需要一个不同的实现而不是一个大的枚举 - 例如一个位流 - 但是我认为这不是重点。)
答案 1 :(得分:1)
如果您还派生Enum
实例,则可以使用fromEnum :: Enum a => a -> Int
和toEnum :: Enum a => Int -> a
在数据类型和与数据定义中的位置对应的整数之间进行转换。由于你在{0}位置有Zero
,依此类推,这正是你想要进出的整数。
但你也应该考虑:addNumber Three Two
的结果是什么?那里没有正确的值,因为你对数字的定义不会达到五。无论你设置什么上限,你都会有一个“部分”函数,对于它的域中的某些值是未定义的。也许对你来说这很好,如果你只是在对数据类型进行练习,但是通常在Haskell程序中我们试图避免部分函数,因为它们会在编译时“应该”被捕获的情况下导致运行时错误。例如,您可以返回Maybe Number
而不是Number
,如果没有有效答案,则返回Nothing
。然后调用者可以明确地处理失败的可能性,而不是隐式地接受它并遭受异常。
答案 2 :(得分:1)
您的号码非常非结构化。因此,如果您想直接定义添加(而不是通过使用标准类型Int
并使用标准+
),则必须执行此操作:
addNumber Zero n = n -- Zero added to anything is n
addNumber One One = Two
addNumber One Two = Three
addNumber Two One = Three
addNumber _ _ = error "overflow, we only go up to Three"
详尽地列出每个案例(幸运的是,由于你只有Three
,所以并不是很多!)。
您可以想象其他稍微多一些的结构数字,您可以使用该结构更经济地定义添加。着名的例子是
data N = Z | S N
...... Peano'的递归数据类型号。