斐波那契位表示 Haskell

Fibonacci Bit Representation Haskell

我已经具备以下功能

toBin, auxBin :: Integer -> [Integer]
toBin 0 = [0]
toBin n = reverse (auxBin n)

auxBin 0 = []
auxBin n = n `mod` 2 : auxBin (n `div` 2)

fib :: Int -> Integer
fib n = fibs !! n
  where
    fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

fibonacci = [fib n | n <- [0..]]

但是当我用 toBin 函数映射 Fibonacci 列表时,我得到了一个不正确的列表:

因为,我得到了这个:

[[0],[1],[1],[1,0],[1,1],[1,0,1],[1,0,0,0],[1,1,0,1],[1,0,1,0,1],[1,0,0,0,1,0]]

但是,我想要这个:

[0,1,10,101,1010,10101,101010,1010101,10101010,101010101]

你能帮帮我吗?

有多种方法可以将数字相加得到一个数字。这是一种方法。可能不是最有效的方法,但另一方面是从较小的函数构建的。

[1,0,1][1,0,0,0][1,1,0,1]这样的值本身就是列表,所以我们首先要做的是对它们进行索引。唯一的麻烦是我们想按降序对它们进行索引。你可以通过反转它们,索引它们,然后再次反转它们来做到这一点,例如:

Prelude> reverse $ zip [0..] $ reverse [1,1,0,1]
[(3,1),(2,1),(1,0),(0,1)]

每个元组的第一个元素是数量级,所以你只需要让它成为十的幂:

Prelude> :m +Data.Bifunctor
Prelude Data.Bifunctor> reverse $ fmap (first (10 ^)) $ zip [0..] $ reverse [1,1,0,1]
[(1000,1),(100,1),(10,0),(1,1)]

现在您可以简单地将元组的元素相乘:

Prelude Data.Bifunctor> reverse $ fmap (uncurry (*) . first (10 ^)) $ zip [0..] $ reverse [1,1,0,1]
[1000,100,0,1]

最后,您可以将所有这些数字相加。其实不需要反转反转列表:

Prelude Data.Bifunctor> sum $ fmap (uncurry (*) . first (10 ^)) $ zip [0..] $ reverse [1,1,0,1]
1101

您可以将这样的组合放在一个函数中,然后将您的值映射到它上面。


一个更有效的解决方案可能是做一个左折叠foldl),例如:

Prelude> foldl (\acc x -> (10 * acc) + x) 0 [1,1,0,1]
1101
Prelude> foldl (\acc x -> (10 * acc) + x) 0 [1,1,1]
111

一个想法可能是用十进制表示法表示二进制值。所以我们 "transform" 2 变成 10.

我们可以通过编写递归函数来做到这一点:

bintodec :: Integral i => i -> i
bintodec 0 = 0
bintodec i = (mod i 2) + 10 * bintodec (div i 2)

这仅适用于正值,但这并不是真正的问题,因为斐波那契数是正数。

现在我们已经有了斐波那契数列的定义,就像您的回答一样:

fibs :: Num n => [n]
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

所以我们唯一还要做的就是 map fibs 的每个元素与 bintodec:

binfibs :: Integral i => [i]
binfibs = map bintodec fibs

那么前15个数字是:

Prelude> take 15 binfibs
[0,1,1,10,11,101,1000,1101,10101,100010,110111,1011001,10010000,11101001,101111001]

这里的好处是我们不使用任何二进制列表来处理它,而是继续在整数世界中工作,这通常更安全。


然而,根据第二个列表,这与斐波那契数列无关。从 0 开始,然后在数字的右端移动一个零或一个。

为此我们可以使用 iterate:

iterate (\x -> 10 * x + 1-(mod x 2)) 0

产生:

Prelude> take 15 $ iterate (\x -> 10 * x + 1-(mod x 2)) 0
[0,1,10,101,1010,10101,101010,1010101,10101010,101010101,1010101010,10101010101,101010101010,1010101010101,10101010101010]