在Haskell中将负基二进制转换为十进制:“需要的实例”

时间:2012-11-06 20:46:03

标签: haskell base-conversion

我必须编写两个函数将十进制数转换为(-2)adian数系统(类似于二进制只有-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的定义需要(Num [Char],Floating Integer)实例。

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

3 个答案:

答案 0 :(得分:5)

您的列表模式匹配语法向后。在_ : _中,第一个参数是列表的头部(一个元素),第二个参数是列表的尾部(另一个列表)。例如与x:xs匹配的"abc"代码为x = 'a' xs = "bc"。因此xs:x应为x:xs。 GHC要求instance of Num [Char]的原因是比较x == 0(和x == 1)。在此,它会尝试将xString == [Char])的类型与0Num a => a)的类型进行匹配,并执行此操作这需要Num的{​​{1}}个实例。

修复方法是:String

要求negbin_dezi (x:xs) n个实例的问题是因为Floating Integer的类型为(**),您希望Floating a => a -> a -> a的类型为(^)(即限制为整数幂。)

完成此操作后,您会发现您的算法由于以下几个原因而无效:

  • 数字0与字符(Num a, Integral b) => a -> b -> a不同,您应该将'0'与字符x'0'进行比较,而不是数字'1'0
  • 1已经是一个字符串,因此xs是一个包含字符串的列表,这不是您想要的。通过删除方括号来解决此问题。
  • 减少的顺序可能是错误的。

另一方面,重复的[xs]语句表明您的代码可能会出现一些优化问题。具体来说,如果您在if中处理空字符串,那么您将不必特殊情况。你可以写它像

negbin_dezi

(这具有功能“更多”的意义,即它在更多输入上定义。)

还有一些事情:

  • 代码是“stringly-typed”:尽管有更多结构,但您的数据仍以字符串形式表示。布尔值列表(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 + ...))ab,...是数字。看看这个,我们可以看到括号内的东西实际上与整个表达式相同,只是从第二个数字开始。这很容易在Haskell中表达(我正在使用list-of-bools的想法。):

    c

    这就是整件事。如果您没有按顺序存储它,那么调用negbin [] = 0 negbin (x:xs) = (if x then 1 else 0) + (-2) * negbin xs 会修复它! (真的很棘手,可以写一下

    reverse

答案 1 :(得分:3)

一些问题:

  1. x == 0x == 1,但xChar,因此您的意思是x == '0'

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

  3. [xs]有一个元素,永远不会是""。请改用基础案例。

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

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

  6. 您经常使用[xs]表示xs。您无需使用方括号来制作列表。

  7. 这是一个有效的重写:

    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
    (它更好,因为它重复使用以前的计算并且非常干净。)

答案 2 :(得分:0)

convB2D::NegaBinary->Integer
convB2D xs|(length xs)==0 =0
          |b=='0' = convB2D(drop 1 xs)
          |b=='1' = val+convB2D(drop 1 xs)
          |otherwise= error "invalid character " 
               where   b=head xs
                       val=(-2)^((length xs)-1)

为我工作。 另一方面,我有转换dec-> nbin:D

的问题