2

我必须编写两个函数,将十进制数字转换为(-2)adian 数字系统(类似于只有-2 的二进制),反之亦然。我已经设法让小数 -> (-2)adian 运行。但是对于 (-2)adian -> decimal 我有一个问题,只是不知道从哪里开始。希望你能帮我

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 所需的 (Num [Char], Floating Integer) 的实例。

任何人都知道为什么它不起作用?请请:)

4

3 回答 3

5

您的列表模式匹配语法倒退。_ : _第一个参数是列表的头部(一个元素),第二个是列表的尾部(另一个列表)。例如x:xs"abc"给匹配x = 'a' xs = "bc"xs:x应该如此x:xs。GHC 要求 , 的原因instance of Num [Char]是比较x == 0(and x == 1)。在这种情况下,它试图将x( String== [Char]) 的类型与0( Num a => a) 的类型相匹配,为此,它需要一个.NumString

修复方法是:negbin_dezi (x:xs) n

要求Floating Integer实例的问题是因为(**)有 type Floating a => a -> a -> a,而你想要(^)哪个有 type (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 中很容易表达(我正在使用 list-of-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
    

    )

于 2012-11-06T21:04:32.630 回答
3

一些问题:

  1. x == 0或者x == 1,但是x是一个Char,所以你的意思是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

您可以重写powersmap ((-2)^) [0..]
甚至更好:powers = 1:map ((-2)*) powers
(它更好,因为它重用了以前的计算并且非常干净。)

于 2012-11-06T20:59:06.263 回答
0

这个

convB2D::NegaBinary->整数
convB2D xs|(长度 xs)==0 =0
          |b=='0' = convB2D(drop 1 xs)
          |b=='1' = val+convB2D(下降 1 xs)
          |否则=错误“无效字符”
               其中 b=head xs
                       val=(-2)^((长度 xs)-1)

为我工作。另一方面,我在转换 dec->nbin 时遇到问题:D

于 2012-11-13T15:27:18.720 回答