Haskell将字符串转换为二进制数

时间:2017-11-15 01:08:01

标签: string haskell functional-programming binary

我需要将一串字符转换为Haskell中的二进制数列表。我写了两个函数来做到这一点,但我不确定如何将它们组合成一个。到目前为止我已经

dec[]=[]
dec(x:xs) = ord(x): dec xs

将列表中的每个字符转换为十进制数字。下一个功能

bin 0 = [0]
bin n| n `mod` 2 == 1 = bin (n `div` 2) ++ [1]
     | n `mod` 2 == 0 = bin (n `div` 2) ++ [0]

将十进制数转换为二进制数。我不确定如何将第二个函数应用于列表中的每个元素,以便将每个字符转换为二进制中的等效字符。我尝试使用where子句:

where n = dec(x:xs) = ord(x): dec xs

但这是无效的,因为同一行上有两个等号。如何实现正确的功能?

2 个答案:

答案 0 :(得分:1)

您可以非常肯定Int将以二进制形式存储。它只显示为十进制,因为它在打印时会转换为十进制。因此,名称dec是用词不当,该函数将String转换为表示每个字符的Unicode值的数字序列。您可以使用map:

来避免显式递归
toUnicode :: String -> [Int]
toUnicode = map ord

请注意,此功能使用所谓的无点样式。缺少预期的参数,但在调用者提供时将传递给map

Bin函数将无法编译,因为它以大写字符开头,使其成为数据构造函数。您应该以小写字符开头命名该函数。根据您的示例输出,您希望二进制表示中的前导零,因此当值变为零时,您无法停止转换。您需要继续,直到您转换了所需的位数(看起来是8)。继续追加到列表也是低效的。最好先添加,然后反转结果。

toBinary :: Int -> [Int]
toBinary = go 8 [] where
    go 0 acc _ = reverse acc
    go n acc x = go (n-1) (bit:acc) x' where
        (x', bit) = x `divMod` 2

在这里,我们使用辅助函数go,它在构建1和0的列表时倒计数剩余的数字。

所以,现在我们有一个将String转换为Int列表的函数,以及一个将Int转换为0/1列表的函数{{1我们希望将它们粘合在一起,以创建一个将Int转换为0/1 String列表的函数。如果我们Int我们的map函数超过toBinary的结果,我们将获得一个列表列表,这些列表必须连接在一起才能形成一个列表。这是一种常见的模式,它有一个函数叫toUnicode

concatMap

在这里,我们使用函数组合首先将stringToBinary :: String -> [Int] stringToBinary = concatMap toBinary . toUnicode 应用于toUnicode,然后将String concatMap应用于结果。

答案 1 :(得分:-1)

我们想要的是String -> Stringdecimal -> binary)类型的函数。你现在拥有的是

dec :: String -> [Int]
bin :: Int -> [Int] -- use *lowercase*

因此,只有这两个函数组合String -> String类型的函数似乎是不可能的。此外,ord不是你想要的。

*Main> dec "123"
[49,50,51]
*Main> bin 123
[0,1,1,1,1,0,1,1]

根据您现在的情况,可能的解决方案是:

*Main Data.Char> toBinary = map intToDigit . bin . read
*Main Data.Char> toBinary "123"
"01111011"

我猜您的意图可能是dec :: String -> Int,然后是bin . dec :: String -> [Int]。您可以按照类型签名重试。