Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 如何实现十进制到二进制的转换_Haskell_Recursion_Functional Programming_Binary_List Comprehension - Fatal编程技术网

Haskell 如何实现十进制到二进制的转换

Haskell 如何实现十进制到二进制的转换,haskell,recursion,functional-programming,binary,list-comprehension,Haskell,Recursion,Functional Programming,Binary,List Comprehension,我在Haskell中实现了一个二进制到十进制的函数,目前正在开发一个将十进制转换为二进制值的函数。(我知道这些功能在某些地方可用,尽管它们不是Prelude.hs的一部分) 我为C型过程语言编写了以下代码,但在将其应用于函数范式时遇到了困难 while(n>0) { 如果(n%2==1) str=str+“1”; 其他的 str=str+“0”; n=n/2; } 我最近才在Haskell开始函数式编程,所以我对函数式思维方式很陌生。我尝试使用递归和列表理解来实现上述操作,但我不确定如何正确放

我在Haskell中实现了一个二进制到十进制的函数,目前正在开发一个将十进制转换为二进制值的函数。(我知道这些功能在某些地方可用,尽管它们不是Prelude.hs的一部分)

我为C型过程语言编写了以下代码,但在将其应用于函数范式时遇到了困难

while(n>0)
{
如果(n%2==1)
str=str+“1”;
其他的
str=str+“0”;
n=n/2;
}
我最近才在Haskell开始函数式编程,所以我对函数式思维方式很陌生。我尝试使用递归和列表理解来实现上述操作,但我不确定如何正确放置保护和逻辑,因为这涉及多个条件。我使用
Int
列表来保存单独的二进制位

--Decimal to binary
toBin:: Int -> [Int]
toBin 0 = [0]
toBin n | (n % 2 == 1) =
        |(n % 2 == 0) = 
我知道上面的模式可以让程序选择guard和end来评估函数。我走错方向了吗

下面是我提出的将任何基数(小于10,代替2)转换为十进制的基本递归

toDecimal :: [Int] -> Int
toDecimal [] = 0
toDecimal (x:xs) = (x * 2 ^(length xs)) + bin xs
0和1是普通情况。 如果n是偶数,那么应该在末尾追加零,否则追加一。
捕捉最后一个guard表达式中的所有内容是一个很好的练习(这就是为什么我使用了与True相同的其他表达式)

没有
%
操作符;您可能正在寻找
`mod`

toBin 0 = [0]
toBin n | n `mod` 2 == 1 = ...
        | n `mod` 2 == 0 = ...
通过保护,可以在函数的多个分支之间进行选择。在这种情况下,如果其相应条件为真,则每个
..
都将是
托宾n
的结果。要将两个列表附加在一起,可以使用
++
运算符,并且
`div`
对应整数除法:

toBin 0 = [0]
toBin n | n `mod` 2 == 1 = toBin (n `div` 2) ++ [1]
        | n `mod` 2 == 0 = toBin (n `div` 2) ++ [0]
然而,这也有一些问题。对于开始,它总是以
0
开始结果,这是冗余的;此外,使用
++[1]
速度较慢,因为它必须遍历整个列表才能在末尾添加一个元素;最好是在执行过程中预先设置每个元素,然后在最后反转结果

为了解决这两个问题,我们将
toBin
拆分为一个主函数和一个辅助函数:

toBin 0 = [0]
toBin n = reverse (helper n)

helper 0 = []
helper n | n `mod` 2 == 1 = 1 : helper (n `div` 2)
         | n `mod` 2 == 0 = 0 : helper (n `div` 2)
在这个版本中,我们使用
操作符,它获取一个值和一个列表,并返回列表,其中的值在列表的开头。我们还将在助手中为0返回一个空结果,并在
toBin
中处理0的大小写,以便结果中不超过所需的0

我们可以通过完全跳过防护来简化
helper
的代码,因为我们只需在右侧再次写入
n`mod`2
的结果:

helper 0 = []
helper n = (n `mod` 2) : helper (n `div` 2)
最后,还有一个函数可以一次完成
div
mod
,效率更高:

helper 0 = []
helper n = let (q,r) = n `divMod` 2 in r : helper q

作为补充说明,这并不是真的将十进制转换为二进制,而是将整数转换为二进制;Haskell实现不太可能以十进制格式存储整数,尽管它们是以十进制格式编写和打印的。要编写十进制到二进制的完整转换,需要一个将十进制字符串解析为整数的函数。

您可以使用
数据中的
展开器
函数。List
模块和
Data.Char中的
intToDigit

toBinary :: Int -> [ Int ]

toBinary 0 = [ 0 ]

toBinary n = toBinary ( n `quot` 2 ) ++ [ n `rem` 2 ]
dec2bin :: Int -> [Char]
dec2bin = reverse . map intToDigit . unfoldr (\x -> if x==0 then Nothing else Just(rem x 2, div x 2))

这里发生的是
unfover
函数使用提供的匿名函数处理输入,直到返回
Nothing
,同时将
Just
中的第一个值聚合到列表中。此列表包含
Int
s,因此需要使用
intToDigit
将它们转换为
Char
s,然后进行反转,因为它们是按相反的顺序收集的。
Char
s列表是Haskell中的一个字符串,所以您就完成了。

所以我最近一直在考虑这个问题,我想出了一个很好的解决方案, 代码是用Haskell编写的,虽然简单但非常有效,但只适用于正数 因为我还没有足够的能力来计算比如说2的补码或者其他类似于二进制代码的东西

binarz :: Int -> [Int]
binarz 0 = []
binarz n = binarz (div n 2) ++ [(mod n 2)] 

您可以使用数据的位移位。位

fromBits :: Bits a => a -> [Bool]
fromBits b
    | b == zeroBits = []
    | otherwise     = testBit b 0 : fromBits (shiftR b 1)

fromBits_ :: Bits a => a -> [Bool]
fromBits_ = reverse . fromBits

“需要一个将十进制字符串解析为整数的函数”-比如,呃,
read
?@DanielFischer:是的,但可能OP正在尝试从头开始实现:)毕竟,
showIntAtBase
也存在。
fromBits :: Bits a => a -> [Bool]
fromBits b
    | b == zeroBits = []
    | otherwise     = testBit b 0 : fromBits (shiftR b 1)

fromBits_ :: Bits a => a -> [Bool]
fromBits_ = reverse . fromBits