我有一个功能
f :: Eq a => a -> a
我知道它最终会重复(我不太确定这个函数是什么叫做;"定期"浮现在脑海中,但是这有点不同,不是'它),我想确定它产生多少个唯一值。
天真,像
import Data.List (nub)
length $ nub $ take n $ iterate f a0
其中a0
是一些初始a
而n
是我知道的一些大数字超过f
的唯一值的数量,会起作用。但是,除了有明显的缺点,我必须猜测或试错n
,这是不切实际的(在我的情况下,无论如何),因为f
可能是耗时的。
找到重复应用此类"重复"生成的唯一值列表的最佳方法是什么? (或者无论正确的术语是什么)Haskell中的函数?
答案 0 :(得分:9)
这确实是https://en.wikipedia.org/wiki/Cycle_detection解决的问题。该页面指出了该问题的几个众所周知的解决方案。
这是一个未经测试的基本乌龟和野兔算法的Haskell实现:
floyd :: Eq a => (a -> a) -> a -> (Int, Int)
floyd f x0 = (lam, mu) where
hare0 = head
[t | (h, t) <- tail $ zip (iterate f x0) (iterate (f . f) x0), h == t]
(mu, tortoise1) = head
[(m, t) | (m, t, h) <- zip3 [0..] (iterate f x0) (iterate f hare0), t == h]
lam = head [l | (l, h) <- zip [1..] (iterate f (f tortoise1)), h == tortoise1]
答案 1 :(得分:2)
好的,这是我评论的非常基本的想法:
import Data.List(unfoldr, genericLength)
cycleLen :: Eq a => (a -> a) -> a -> Integer
cycleLen f a0 = 1 + genericLength (unfoldr gen [a0])
where gen xs@(x:_) =
let a' = f x
in if a' `elem` xs then Nothing else Just (a',a':xs)
gen [] = undefined
让我们用一些非常基本的功能测试它:
test :: Int -> Int
test x = (x*2+1) `mod` 10
λ> cycleLen test 0
5
λ> take 6 (iterate test 0)
[0,1,3,7,5,1]
λ> cycleLen test 4
2
λ> take 6 (iterate test 4)
[4,9,9,9,9,9]
似乎很好;)
但要注意:它肯定不是最佳方式 - 但它适用于我认为的小东西