在 Haskell 中将负基二进制转换为十进制:"Instances of .. required"



我必须编写两个函数,将十进制数字转换为(-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'进行比较,而不是将数字与01进行比较。
  • 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 + ...))abc,...是数字。看看这个,我们可以看到括号内的东西实际上与整个表达式相同,只是从第二个数字开始。这在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
    

    )

一些问题:

  1. x == 0x == 1,但xChar,所以你的意思是x == '0'

  2. 你写(xs:x).列表末尾没有匹配模式。也许使用先反转列表的帮助程序函数。

  3. [xs]有一个元素,永远不会""。请改用基本情况。

  4. 模式匹配比相等性检查更有帮助。

  5. **用于浮点幂,^用于整数幂

  6. 你经常在你的意思是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 时遇到问题

最新更新