当前位置:  开发笔记 > 运维 > 正文

使用商店comonad表现Conway的生命游戏

如何解决《使用商店comonad表现Conway的生命游戏》经验,为你挑选了1个好方法。

我使用Store comonad 编写了Conway的生命游戏的简单实现(参见下面的代码).我的问题是,从第五次迭代开始,网格生成明显变慢.我的问题与我使用Store comonad的事实有关吗?还是我犯了一个明显的错误?据我所知,其他的实现,这是基于拉链comonad,是有效的.

import Control.Comonad

data Store s a = Store (s -> a) s

instance Functor (Store s) where
    fmap f (Store g s) = Store (f . g) s

instance Comonad (Store s) where
    extract (Store f a) = f a
    duplicate (Store f s) = Store (Store f) s

type Pos = (Int, Int)

seed :: Store Pos Bool
seed = Store g (0, 0)
    where
        g ( 0,  1) = True
        g ( 1,  0) = True
        g (-1, -1) = True
        g (-1,  0) = True
        g (-1,  1) = True
        g _        = False

neighbours8 :: [Pos]
neighbours8 = [(x, y) | x <- [-1..1], y <- [-1..1], (x, y) /= (0, 0)]

move :: Store Pos a -> Pos -> Store Pos a
move (Store f (x, y)) (dx, dy) = Store f (x + dx, y + dy)

count :: [Bool] -> Int
count = length . filter id

getNrAliveNeighs :: Store Pos Bool -> Int
getNrAliveNeighs s = count $ fmap (extract . move s) neighbours8

rule :: Store Pos Bool -> Bool
rule s = let n = getNrAliveNeighs s
        in case (extract s) of
            True  -> 2 <= n && n <= 3
            False -> n == 3

blockToStr :: [[Bool]] -> String
blockToStr = unlines . fmap (fmap f)
    where
        f True  = '*'
        f False = '.'

getBlock :: Int -> Store Pos a -> [[a]]
getBlock n store@(Store _ (x, y)) =
    [[extract (move store (dx, dy)) | dy <- yrange] | dx <- xrange]
    where
        yrange = [(x - n)..(y + n)]
        xrange = reverse yrange

example :: IO ()
example = putStrLn
        $ unlines
        $ take 7
        $ fmap (blockToStr . getBlock 5)
        $ iterate (extend rule) seed

leftaroundab.. 6

商店comonad本身并不真正存储任何东西(除了抽象意义上的函数是一个"容器"),但必须从头开始计算它.这显然在几次迭代中变得非常低效.

如果您只是s -> a通过一些备忘录来备份函数,那么您可以在不更改代码的情况下缓解此问题:

import Data.MemoTrie

instance HasTrie s => Functor (Store s) where
  fmap f (Store g s) = Store (memo $ f . g) s

instance HasTrie s => Comonad (Store s) where
  extract (Store f a) = f a
  duplicate (Store f s) = Store (Store f) s

没有测试这是否真的给出了可接受的性能.



1> leftaroundab..:

商店comonad本身并不真正存储任何东西(除了抽象意义上的函数是一个"容器"),但必须从头开始计算它.这显然在几次迭代中变得非常低效.

如果您只是s -> a通过一些备忘录来备份函数,那么您可以在不更改代码的情况下缓解此问题:

import Data.MemoTrie

instance HasTrie s => Functor (Store s) where
  fmap f (Store g s) = Store (memo $ f . g) s

instance HasTrie s => Comonad (Store s) where
  extract (Store f a) = f a
  duplicate (Store f s) = Store (Store f) s

没有测试这是否真的给出了可接受的性能.

推荐阅读
臭小子
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有