我必须编写两个函数,将十进制数字转换为(-2)阿迪安数字系统(类似于二进制,只有-2),反之亦然。 我已经设法让十进制 -> (-2)adian 运行。 但是对于 (-2)adian -> 十进制,我遇到了问题,只是不知道从哪里开始。 希望你能帮助我
type NegaBinary = String
-- Function (-2)adisch --> decimal
negbin_dezi :: NegaBinary -> Integer -> Integer
negbin_dezi (xs:x) n
| (x == 0) = if ([xs] == "") then 0 else (negbin_dezi [xs] (n+1))
| (x == 1) = if ([xs] == "") then (-2)**n else (-2)**n + (negbin_dezi [xs] (n+1))
它总是抛出: "定义negbin_dezi所需的(数字 [字符],浮点整数)的实例。
有人知道为什么它不起作用吗? 请请:)
你的列表模式匹配语法是向后的。在_ : _
中,第一个参数是列表的头部(一个元素),第二个参数是列表的尾部(另一个列表)。例如x:xs
与"abc"
匹配,x = 'a'
xs = "bc"
。所以xs:x
应该是x:xs
.GHC要求instance of Num [Char]
的原因是比较x == 0
(和x == 1
)。在这种情况下,它试图将x
的类型(String
==[Char]
)与0
的类型(Num a => a
)相匹配,为此,它需要一个Num
实例来String
。
修复为:negbin_dezi (x:xs) n
要求Floating Integer
实例的问题是(**)
具有类型Floating a => a -> a -> a
,而您想要(^)
具有类型(Num a, Integral b) => a -> b -> a
(即它仅限于整数幂)。
完成此操作后,您会发现您的算法不起作用,原因如下:
- 数字 0 与字符
'0'
不同,您应该将x
与字符'0'
和'1'
进行比较,而不是将数字与0
和1
进行比较。 xs
已经是一个字符串,所以[xs]
是一个包含字符串的列表,这不是你想要的。这是通过删除方括号来修复的。- 可能减少的顺序是错误的。
另一方面,重复的if
语句表明您的代码可能会发生一些优化。具体来说,如果您将空字符串作为negbin_dezi
的一部分进行处理,则不必对其进行特殊处理。你可以把它写成这样
negbin_dezi "" _ = 0
negbin_dezi (x:xs) n
| n == '0' = negbin_dezi xs (n+1)
| n == '1' = (-2)^n + negbin_dezi
(这有一个好处,即函数是"更全面的",即它是在更多的输入上定义的。
还有几件事:
- 代码是"字符串类型"的:尽管具有更多结构,但您的数据仍表示为字符串。布尔值列表(
[Bool]
)会好得多。 该算法可以调整为更干净。对于以下内容,我假设您像
"01" = -2
"001" = 4
一样存储它,等等。如果是这样,那么我们知道number = a + (-2) * b + (-2)^2 * c ... = a + (-2) * (b + (-2) * (c + ...))
a
、b
、c
,...是数字。看看这个,我们可以看到括号内的东西实际上与整个表达式相同,只是从第二个数字开始。这在Haskell中很容易表达(我使用的是bools列表的想法)。negbin [] = 0 negbin (x:xs) = (if x then 1 else 0) + (-2) * negbin xs
这就是全部。如果您没有按该顺序存储它,那么调用
reverse
可以解决这个问题!(真的很棘手,可以写negbin = foldr (x n -> (if x then 1 else 0) + (-2)*n) 0
)
一些问题:
-
x == 0
或x == 1
,但x
是Char
,所以你的意思是x == '0'
。 -
你写
(xs:x)
.列表末尾没有匹配模式。也许使用先反转列表的帮助程序函数。 -
[xs]
有一个元素,永远不会""
。请改用基本情况。 -
模式匹配比相等性检查更有帮助。
-
**
用于浮点幂,^
用于整数幂 -
你经常在你的意思是
xs
的地方使用[xs]
。您无需添加方括号即可列出列表。
这是一个有效的重写:
negbin_dezi1 :: NegaBinary -> Integer
negbin_dezi1 xs = negbin (reverse xs) 0
negbin [] _ = 0
negbin (x:xs) n
| x == '0' = negbin xs (n+1)
| x == '1' = (-2)^n + (negbin xs (n+1))
使用模式匹配会更好:
negbin_dezi2 :: NegaBinary -> Integer
negbin_dezi2 xs = negbin (reverse xs) 0 where
negbin [] _ = 0
negbin ('0':xs) n = negbin xs (n+1)
negbin ('1':xs) n = (-2)^n + negbin xs (n+1)
但也许将"0"转换为0 和将"1"转换为 1 并乘以它会更好:
val :: Char -> Int
val '0' = 0
val '1' = 1
negbin_dezi3 :: NegaBinary -> Integer
negbin_dezi3 xs = negbin (reverse xs) 0 where
negbin [] _ = 0
negbin (x:xs) n = val x * (-2)^n + negbin xs (n+1)
不过,我不会这样写:
一种完全不同的方法是一次考虑整个事情。
"10010" -rev> [0,1,0,0,1] -means> [ 0, 1, 0, 0, 1 ]
[(-2)^0, (-2)^1, (-2)^2, (-2)^3, (-2)^4]
所以让我们做两个列表
powers = [(-2)^n | n <- [0..]]
coefficients = reverse.map val $ xs
并乘以它们
zipWith (*) powers coefficients
然后加起来,给出:
negbin_dezi4 xs = sum $ zipWith (*) powers coefficients
where powers = [(-2)^n | n <- [0..]]
coefficients = reverse.map val $ xs
你可以把powers
改写成map ((-2)^) [0..]
,
甚至更好:powers = 1:map ((-2)*) powers
。
(它更好,因为它重用了以前的计算并且非常干净。
这个
convB2D::NegaBinary->Integer 卷维B2D xs|(长度 xs)==0 =0 |b=='0' = convB2D(drop 1 xs) |b=='1' = val+convB2D(drop 1 xs) |否则= 错误"无效字符" 其中 b=头 xs val=(-2)^((length xs)-1)
为我工作。 另一方面,我在转换 dec->nbin :D 时遇到问题