我发现这段代码有效,但我不明白为什么会这样。它将Int转换为二进制表示。
repBinario::Int -> Int
repBinario 0 = 0
repBinario x = 10 * repBinario (x `div` 2) + x `mod` 2
我知道div
和mod
做了什么。但是,它如何将mod
的每个数字放在一起?
答案 0 :(得分:6)
简而言之,它在每次迭代时将累计结果乘以10
。
为了更清楚地了解正在发生的事情,我们可以将您的功能划分为两个更简单的功能。第一个将整数转换为二进制数字列表。然后另一个将完成困扰你的事情:将二进制数字列表连接成一个整数。
extractBinDigits :: Int -> [Int]
extractBinDigits =
unfoldr (\x -> if x == 0 then Nothing else Just (mod x 2, div x 2))
concatDigits :: [Int] -> Int
concatDigits =
foldr (\a b -> a + b * 10) 0
如您所见,我们只需将每个步骤上的累加器乘以10
,然后将每个数字添加到其中。
然后你原来的功能变成了这个:
repBinario :: Int -> Int
repBinario =
concatDigits . extractBinDigits
现在,我们可以检查和重复使用我们程序中更精细的部分,为我们提供更大的灵活性。例如,通过添加另一个简单函数,您现在可以一次性将整数转换为字符串:
showDigits :: [Int] -> String
showDigits =
reverse . map (chr . (+ 48))
repStringyBinario :: Int -> String
repStringyBinario =
showDigits . extractBinDigits
答案 1 :(得分:5)
我们来看一个例子,然后:
repBinario 5
repBinario 5
的替代定义:
10 * repBinario (5 `div` 2) + 5 `mod` 2
减少div
和mod
:
10 * repBinario 2 + 1
^
我们在这里制作了第一个数字,标有^
。
repBinario 2
的替代定义:
10 * (10 * repBinario (2 `div` 2) + 2 `mod` 2) + 1
^
减少div
和mod
:
10 * (10 * repBinario 1 + 0) + 1
^ ^
repBinario 1
的替代定义:
10 * (10 * (10 * repBinario (1 `div` 2) + 1 `mod` 2) + 0) + 1
^ ^
减少div
和mod
:
10 * (10 * (10 * repBinario 0 + 1) + 0) + 1
^ ^ ^
repBinario 0
的替代定义:
10 * (10 * (10 * 0 + 1) + 0) + 1
^ ^ ^
减少
101
在每一步中,(`mod` 2)
获得最不重要的二进制数字,(`div` 2)
将数字向右移动,丢弃该数字并将其余数字递归传递给{ {1}}。最后,我们执行相反的过程:divBinario
将当前数字添加到结果中,(+ d)
将数字向左移动,以便我们可以添加更多数字。
你得到的是一个十进制数,看起来与原始输入的二进制表示相同。
如果您按(* 10)
移除乘法,则会得到10
,这是一个为您提供数字的人口数的函数 - popCount
的数量二进制表示中的位:
1
答案 2 :(得分:5)
我认为最好手动计算一个小值的这个函数 - 这是可能的,因为这是一个纯函数,因此你可以用它的定义(即右边)取代左手边 - 花哨的计算机科学这个特征的词是“参照透明度”。
repBinario 24 = 10 * repBinario (24 `div` 2) + 24 `mod` 2
= 10 * repBinario 12 + 0
= 10 * (10 * repBinario (12 `div` 2) + 12 `mod` 2)
= 100 * repBinario 6 + 0
= 100 * (10 * repBinario (6 `div` 2) + 6 `mod` 2)
= 1000 * repBinario 3 + 0
= 1000 * (10 * repBinario (3 `div` 2) + 3 `mod` 2)
= 10000 * repBinario 1 + 1000 * 1
= 10000 (10 * repBinario (1 `div` 2) + 1 `mod` 2) + 1000
= 10000 (10 * repBinario 0 + 1) + 1000
= 10000 (10 * 0 + 1) + 1000
= 10000 * 1 + 1000
= 11000
在这些步骤中,我只是根据其定义评估函数,并使用整数加法/乘法服从分布律的事实。