用haskell的方式对动画程序进行了一点尝试

14 views
Skip to first unread message

黄毅

unread,
Mar 29, 2010, 12:31:03 PM3/29/10
to haskellcn
这个程序比较简单,每一次循环都得到整个世界的一个新状态,没有ui,只有对物体坐标的计算。
我比较困惑,是不是用函数式的方式写这种程序都得这么弄,对状态的更新都需要得到新的状态。

class (Show m) => Widget m where
update :: Integer -> m -> m

instance (Num a,Num b) => Num (a,b) where
(x1,y1) + (x2,y2) = (x1+x2,y1+y2)
(x1,y1) * (x2,y2) = (x1*x2,y1*y2)
(x1,y1) - (x2,y2) = (x1-x2,y1-y2)
negate (x,y) = (negate x,negate y)
abs (x,y) = (abs x,abs y)
signum (x,y) = (signum x,signum y)
fromInteger i = (fromInteger i,fromInteger i)

data Sqare = Sqare{pos::(Integer,Integer),speed::(Integer,Integer)}
deriving(Show)

instance Widget Sqare where
update t w@(Sqare p s) = w{pos=p+s*(t,t)}

data World a = World [a]
deriving(Show)

instance (Widget a) => Widget (World a) where
update t (World children) = World (map (update t) children)

run::(Widget m)=>Integer->m->IO()
run 0 world = do
putStrLn (show world)
run (-1) world = do
putStrLn (show world)
run (-1) (update 1 world)
run times world = do
putStrLn (show world)
run (times-1) (update 1 world)

main = do
let world = World [Sqare (1,1) (1,1),Sqare (100,100) (-1,1),Sqare
(100,100) (1,-1)]
run 10 world

Wensheng

unread,
Mar 29, 2010, 3:53:18 PM3/29/10
to haskell.cn
一行不需用do, "run 0 world" 不用do, main也不用,直接let ... in 就行了。还有 run (-1)
world 不对。其他看不太明白,因为不知道干什么。

Albert Lee

unread,
Mar 29, 2010, 9:31:42 PM3/29/10
to hask...@googlegroups.com
大概看明白了。

run -1 world 是无限循环
run times world 是运行 times 次。
每次运行时,对  World [Widget] 对象里面的 Widget map update 函数, update 是计算新的位置,根据之前的 pos 和 speed 来计算,获取新的位置。



2010/3/30 Wensheng <wenshe...@gmail.com>
--
您收到此邮件是因为您订阅了 Google 网上论坛的“haskell.cn”论坛。
要向此网上论坛发帖,请发送电子邮件至 hask...@googlegroups.com
要取消订阅此网上论坛,请发送电子邮件至 haskellcn+...@googlegroups.com
若有更多问题,请通过 http://groups.google.com/group/haskellcn?hl=zh-CN 访问此网上论坛。


黄毅

unread,
Mar 29, 2010, 9:37:26 PM3/29/10
to hask...@googlegroups.com
2010/3/30 Albert Lee <hanzh...@gmail.com>:

> 大概看明白了。
>
> run -1 world 是无限循环
> run times world 是运行 times 次。
> 每次运行时,对  World [Widget] 对象里面的 Widget map update 函数, update 是计算新的位置,根据之前的 pos
> 和 speed 来计算,获取新的位置。

哈哈,是这样的,昨晚写得比较匆忙。
想了一下,从模型上来看,每次从旧的状态计算出新的状态,确实是正确的。
但从执行来看,World里面有大量物体的情况下,动画的每一帧都需要创建大量的对象,而且旧的对象直接被丢弃不再被使用,似乎有点浪费。

--
http://codeplayer.blogspot.com/

Albert Lee

unread,
Mar 29, 2010, 11:12:30 PM3/29/10
to hask...@googlegroups.com
对Haskell 内部的数据存储方式还不是太了解, 但感觉这个确实不高效。 有一些库提供高效的存储结构,比如 array 之类的。
另外 State Monad 就是针对这种场景, 可以把 World 参数隐藏起来,不需要在函数中传来传去的。

2010/3/30 黄毅 <yi.cod...@gmail.com>

Jack,Shen

unread,
Mar 30, 2010, 1:15:02 AM3/30/10
to hask...@googlegroups.com
可能用 IORef 或 STRef 会快点(ST --  state thread 看名字就知道是用来干这活的),
Ref的内容,应该不会使用复制的模式,进行传递。

可以定义 data Square a b = Square !a !b 减少内存使用

使用UMArray的话,修改应该不会把原来的整个数据对象重写。

2010/3/30 Albert Lee <hanzh...@gmail.com>
Reply all
Reply to author
Forward
0 new messages