我正在尝试创建一个函数,该函数使用遗传算法递归地玩所有可能的井字游戏,然后返回一个 (wins,losses,ties) 的元组。但是,下面的函数在这样调用时总是会溢出堆栈:
scoreOne :: UnscoredPlayer -> [String] -> ScoredPlayer
scoreOne player boards = ScoredPlayer (token player) (chromosome player) (evaluateG $! testPlayer player boards)
...
let results = map (\x->scoreOne x boards) players
print (maximum results)
哪里players
是染色体列表。溢出不会发生在只有 1 名玩家的情况下,但会发生在 2 名玩家身上。
编辑:如果函数以下列方式调用,它不会溢出堆栈。
let results = map (\player -> evaluateG (testPlayer player boards)) players
print (maximum results)
但是,以下方式确实会溢出堆栈。
let results = map (\player -> ScoredPlayer (token player) (chromosome player) (evaluateG $! testPlayer player boards)) players
作为参考,ScoredPlayer
定义为(字符串为玩家标记,[Int] 为染色体,Float 为分数):
data ScoredPlayer = ScoredPlayer String ![Int] !Float deriving (Eq)
根据我对 Haskell 的了解,该playAll'
函数不是尾递归的,因为foldl'
我正在使用的调用正在对函数结果执行进一步处理。但是,我不知道如何消除foldl'
呼叫,因为需要确保玩所有可能的游戏。有什么方法可以重构函数,使它是尾递归的(或者至少不会溢出堆栈)?
在此先感谢,并为大量代码清单感到抱歉。
playAll' :: (Num a) => UnscoredPlayer -> Bool -> String -> [String] -> (a,a,a) -> (a,a,a)
playAll' player playerTurn board boards (w,ls,t)=
if won == self then (w+1,ls,t) -- I won this game
else
if won == enemy then (w,ls+1,t) -- My enemy won this game
else
if '_' `notElem` board then (w,ls,t+1) -- It's a tie
else
if playerTurn then --My turn; make a move and try all possible combinations for the enemy
playAll' player False (makeMove ...) boards (w,ls,t)
else --Try each possible move against myself
(foldl' (\(x,y,z) (s1,s2,s3) -> (x+s1,y+s2,z+s3)) (w,ls,t)
[playAll' player True newBoard boards (w,ls,t)| newBoard <- (permute enemy board)])
where
won = winning board --if someone has one, who is it?
enemy = (opposite.token) player --what player is my enemy?
self = token player --what player am I?