繁体   English   中英

Haskell:对数据类型的算术运算

[英]Haskell: arithmetic operations on data types

我试图了解数据类型,并且要这样做,我想尝试模拟整数值。 我用以下方式定义它:

data Number = Zero | One | Two | Three deriving (Eq,Ord,Show)

因此,基本上,我希望能够使用这种类型的元素进行基本的算术运算。 类似于

addNumber :: Number -> Number -> Number

像addNumber一二这样调用将得到三。 但是,我真的不确定如何正确执行此操作。 我认为可以通过相互比较Number来做到这一点,但是要从中得到任何东西,我需要能够以这种特定顺序访问下一个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

至少将其“转换”为整数,以便实际上可以对其进行算术运算。 但是,这感觉有点静态,整体上是错误的(我可能可以通过开关,防护罩或类似的东西更快地完成此操作。是否有更好的方法?

我假设您希望避免使用内置算术-否则,因为您观察到可以将其转换为内置数字,执行算术并转换回去,但是从“学习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

当然,这会稍微降低效率。 并且您不想对较大的数字类型执行此操作。 但这需要更少的手指打字。 (无论如何,对于较大的数字类型,您可能想要的是不同于大枚举的实现(例如,比特流),但是我认为这是重点。)

如果还派生一个Enum实例,则可以使用fromEnum :: Enum a => a -> Int toEnum :: Enum a => Int -> a fromEnum :: Enum a => a -> InttoEnum :: Enum a => Int -> a在数据类型和与它们在数据定义中位置相对应的整数之间进行转换。 既然你有Zero在第0位置,等等,这将是正是你想要什么要和整数。

但是您还应该考虑: addNumber Three Two的结果是什么? 那里没有正确的值,因为您对数字的定义不会达到5。 无论您设置了什么上限,您都将拥有一个“部分”函数,该函数在其域中的某些值上是未定义的。 如果您只是对数据类型进行练习,那么这可能对您来说很好,但是通常在Haskell程序中,我们会尽量避免使用部分函数,​​因为在“应该”在编译时被捕获的情况下,它们可能会导致运行时错误。 例如,您可以返回Maybe Number而不是Number ,如果没有有效答案,则返回Nothing 然后,调用者可以显式应对失败的可能性,而不是隐式接受失败并遭受异常。

您的电话号码非常混乱。 这样,如果您想直接定义加法(而不是通过标准类型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”数字的递归数据类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM