В моем другом ответе я покажу, как это сделать с CReal, чтобы ответить на ваш вопрос о том, можно ли это сделать.Но на самом деле я не думаю, что это хорошая идея, потому что она требует больше энергии, чем необходимо.Просто чтобы дать представление о том, что я имею в виду для «более принципиального» подхода, вот что я думаю:
bits :: Rational -> [Int]
bits n = whole : bits (2*frac) where
(whole, frac) = properFraction n
В действии:
> take 65 . bits $ 1/3
[0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1]
Вы будетеобратите внимание, что это значительно быстрее, чем подход CReal в другом ответе.Он также должен иметь более высокую производительность памяти, даже если вы переключите другой ответ с CReal на Rational, поскольку он сохраняет дробь сверху ограниченной 1 (тогда как другое решение добавляет ~ 1 бит за итерацию).Это можно сделать еще быстрее, заметив, когда начинается цикл.Вот функция, которая возвращает цикл в легко наблюдаемом виде:
import Data.Set (Set)
import qualified Data.Set as S
data BitsRep
= Loop Rational [Int]
| Lollipop [Int] [Int]
deriving (Eq, Ord, Read, Show)
-- always returns a Lollipop when given an empty set
bitsRaw :: Set Rational -> Rational -> BitsRep
bitsRaw s n = case S.member n s of
True -> Loop n []
False -> case bitsRaw (S.insert n s) (2*frac) of
Lollipop prefix loop -> Lollipop (whole:prefix) loop
Loop n' loop -> (if n == n' then Lollipop [] else Loop n') (whole:loop)
where
(whole, frac) = properFraction n
Если вы действительно хотите, чтобы он был бесконечным списком, подойдет короткая оболочка и значительно сократит вычисления, необходимые после того, как точка цикла станетдостиг:
bits :: Rational -> [Int]
bits n = prefix ++ cycle loop where
Lollipop prefix loop = bitsRaw S.empty n