简体   繁体   English

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

[英]Haskell converting string to binary number

I need to convert a string of chars to a list of binary numbers in Haskell. 我需要将一个字符串转换为Haskell中的二进制数列表。 I've written two functions to do this, but I'm not sure how to combine them into one. 我已经编写了两个函数来执行此操作,但是我不确定如何将它们组合为一个。 So far I have 到目前为止,我有

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

to convert every char in the list into a decimal number. 将列表中的每个字符转换为十进制数。 The next function 下一个功能

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

converts a decimal number to its binary equivalent. 将十进制数转换为其等效的二进制数。 I'm not sure how to apply the second function to every element in the list, in order to convert every char to its equivalent in binary. 我不确定如何将第二个函数应用于列表中的每个元素,以便将每个字符转换为等效的二进制值。 I tried to use the where clause: 我尝试使用where子句:

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

but this is not valid as there are two equals signs on the same line. 但这是无效的,因为同一行上有两个等号。 How can I achieve the correct functionality? 如何获得正确的功能?

You can be pretty certain that an Int will be stored in binary. 您可以确定一个Int将以二进制形式存储。 It only appears to be in decimal because it is converted to decimal when you print it. 它仅显示为十进制,因为在打印时会转换为十进制。 So, the name dec is a misnomer, that function is converting a String into a sequence of numbers that represent the Unicode value of each character. 因此,名称dec是用词不当,该函数将String转换为代表每个字符的Unicode值的数字序列。 You can avoid explicit recursion by using map: 您可以使用map避免显式递归:

toUnicode :: String -> [Int]
toUnicode = map ord

Note that this function uses so-called point-free style. 请注意,此函数使用所谓的无点样式。 The expected argument is missing, but will be passed to map when supplied by the caller. 预期的参数丢失,但是在调用方提供时将传递给map

The Bin function will not compile because it starts with an upper case character, making it a data constructor. Bin函数不会编译,因为它以大写字母开头,使其成为数据构造函数。 You should name the function starting with a lower case character. 您应以小写字母开头的函数命名。 According to your example output, you want leading zeros in your binary representations, so you can't stop conversion when the value becomes zero. 根据示例输出,您希望二进制表示形式中的前导零,因此当值变为零时就不能停止转换。 You need to continue until you have converted the desired number of digits, which appears to be 8. It is also inefficient to keep appending to a list. 您需要继续操作,直到转换了所需的数字位数(看来是8)为止。保持附加到列表的效率也很低。 It is better to prepend, and then reverse the result. 最好先添加,然后反转结果。

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

Here, we use a helper function, go which counts down the number of remaining digits as it builds up the list of 1's and 0's. 在这里,我们使用一个辅助函数go ,它在建立1和0的列表时对剩余位数进行计数。

So, now we have a function to convert a String into a list of Int s, and a function to convert an Int into a list of 0/1 Int s, and we want to glue them together to make a function that converts a String to a list of 0/1 Int s. 因此,现在我们有了一个将String转换为Int列表的函数,以及一个将Int转换为0/1 Int列表的函数,并且我们希望将它们粘合在一起以构成一个将String转换为函数的函数。到0/1 Int列表。 If we map our toBinary function over the result of toUnicode , we will get a list of lists, which must be concatenated to form a single list. 如果map toBinary函数maptoUnicode的结果上,则会得到一个列表列表,该列表必须串联起来形成一个列表。 This is such a common pattern that there's a function for that called, concatMap : 这是一种常见的模式,因此有一个名为concatMap的函数:

stringToBinary :: String -> [Int]
stringToBinary = concatMap toBinary . toUnicode

Here we use function composition to first apply toUnicode to the String , and then concatMap the toBinary over the result. 在这里,我们使用函数组合首先将toUnicode应用于String ,然后对结果进行concatMap toBinary

What we want is a function of type String -> String ( decimal -> binary ). 我们想要的是一个类型为String -> Stringdecimal -> binary )的函数。 What you have now is 您现在拥有的是

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

So it seems impossible to compose a function of type String -> String only with these two. 因此,似乎不可能仅用这两个组成String- String -> String类型的函数。 Besides, ord is not what you want. 此外, ord不是您想要的。

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

From what you have now, the possible solution would be: 从现在开始,可能的解决方案是:

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

I guess your intention may be dec :: String -> Int , then bin . dec :: String -> [Int] 我想您的意图可能是dec :: String -> Int ,然后是bin . dec :: String -> [Int] bin . dec :: String -> [Int] . bin . dec :: String -> [Int] You can follow the type signature and retry. 您可以遵循类型签名并重试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM