Re[3]: Немного поясните про чистую функциональщину
От: thesz Россия http://thesz.livejournal.com
Дата: 08.09.07 23:26
Оценка: 8 (1)
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, thesz, Вы писали:


T>>Бесконечный список можно заменить на любую другую бесконечную структуру, это несложно.


К>А разреженный список как сделать без State?


data T = T String deriving Show

toInt (T s) = (read s)::Int
fromInt i = T $ show i

cache =
    map (map fromInt)
    $ map (\(f,t) -> [f..t-1])
    $ iterate (\(a,b) -> (b,b*2)) (1,2)

fetchCache i = take 1 i cache
    where
        take ofs 1 (xs:_) = xs !! (i-ofs)
        take ofs n (_:xss) = take (ofs*2) (div n 2) xss


Результаты:
*Main> fetchCache 2048
T "2048"
(0.02 secs, 0 bytes)
*Main> fetchCache 8192
T "8192"
(0.00 secs, 0 bytes)
*Main> fetchCache 32768
T "32768"
(0.00 secs, 0 bytes)
*Main> fetchCache 131072
T "131072"
(0.00 secs, 0 bytes)
*Main> fetchCache 131071
T "131071"
(0.03 secs, 6414520 bytes)
*Main> fetchCache 262144
T "262144"
(0.00 secs, 264588 bytes)
*Main> fetchCache 524288
T "524288"
(0.00 secs, 266712 bytes)
*Main> fetchCache 524287
T "524287"
(0.33 secs, 19143472 bytes)
*Main>


Вот кэш:
*Main> take 5 cache
[[T "1"],[T "2",T "3"],[T "4",T "5",T "6",T "7"],[T "8",T "9",T "10",T "11",T "1
2",T "13",T "14",T "15"],[T "16",T "17",T "18",T "19",T "20",T "21",T "22",T "23
",T "24",T "25",T "26",T "27",T "28",T "29",T "30",T "31"]]


Видно, что вычисление первых элементов в подсписке дешево, последних дорогое.

По идее, лучше сделать по твоей мысли с бесконечным деревом, где левая половина содержит данные для base..base*2-1, правая — все остальные.

Вот, я и код написал:
data T = T String deriving Show

toInt (T s) = (read s)::Int
fromInt i = T $ show i

data C a = N a | C (C a) (C a)    -- left subtree is finite, right subtree - infinite

mapC f (N a) = N $ f a
mapC f (C a b) = C (mapC f a) (mapC f b)

cache = mapC fromInt $ heap 1 1
    where
        heap ofs base = C (c ofs (ofs+base-1)) (heap base2 base2)
            where
                base2 = base*2
        c from to
            | from == to = N from
            | otherwise = C (c from mid) (c (mid+1) to)
            where
                mid = div (to+from) 2

showC 0 _ = "..."
showC n (N x) = "(N "++show x++")"
showC n (C l r) = "(C "++showC (n-1) l++" "++showC (n-1) r++")"

fetchCache i = findLeaf offset (offset*2-1) left
    where
        findLeft ofs (C l r)
            | i >= ofs*2 = findLeft (ofs*2) r
            | otherwise = (ofs,l)
        (offset,left) = findLeft 1 cache
        findLeaf from to (N x) = x
        findLeaf from to (C l r)
            | i > mid = findLeaf (mid+1) to r
            | otherwise = findLeaf from mid l
            where
                mid = div (from+to) 2


А вот результаты работы:
*Main> fetchCache 4
T "4"
(0.02 secs, 266976 bytes)
*Main> fetchCache 7
T "7"
(0.02 secs, 530516 bytes)
*Main> fetchCache 15
T "15"
(0.00 secs, 266952 bytes)
*Main> fetchCache 31
T "31"
(0.00 secs, 530028 bytes)
*Main> fetchCache 142
T "142"
(0.00 secs, 267172 bytes)
*Main> fetchCache 284
T "284"
(0.00 secs, 531596 bytes)
*Main> fetchCache 10000
T "10000"
(0.00 secs, 268288 bytes)
*Main> fetchCache 100000
T "100000"
(0.00 secs, 533580 bytes)
*Main>


Память зря не расходуется, время не растет.

Чудеса!

T>>Добавлю, что rand с типом rand :: RndState -> (Int,RndState) может быть сконвертирован в бесконечный список псевдослучайных чисел типа Int, с которым работать достаточно удобно, например, обычной сверткой.


К>Задумался над тем, как унифицировать монады State и List применительно к рандому.


Боюсь, не удастся.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.