0

嘿,我已经将此代码段实现为用于 alpha-beta 修剪功能的移动排序系统。它确实加快了我的代码速度,但是当我分析我的代码时,我发现它非常笨拙。

    move_ord [] (primary_ord,secondary_ord) = primary_ord ++ secondary_ord 
    move_ord (y:ys) (primary_ord,secondary_ord) = case no_of_pebbles state y of
        0        -> move_ord ys (primary_ord,secondary_ord)
        13       -> move_ord ys (y : primary_ord,secondary_ord)
        x        
            | 7 - y == x -> move_ord ys (y : primary_ord,secondary_ord)
            | otherwise     -> move_ord ys (primary_ord,y : secondary_ord)

它旨在将具有特定 pebble 值(13 和 7-y==x)的移动放在列表的前面。同时也过滤掉了0个鹅卵石的非法走法。

Pebbles 存储为 Int。y 是一个整数。

先感谢您。

4

3 回答 3

2

的元素出现的顺序primary_ord重要吗?

不,不是的。我正在命令分支首先检查 alpha-beta 截止值。我概述的案例更有可能在评估的下一个分支上触发修剪。尽管由于我没有其他信息,只要它们出现在其他案例的前面,它们就可以按任何顺序排列。

在这种情况下,您应该在找到它们后立即交付它们,而只推迟交付坏的。

如果move_ord是 - 除了在递归调用中 - 只([],[])作为第二个参数调用,我建议

move_ord = go []
  where
    go acc (y:ys) = case no_of_pebbles state y of
                      0             -> go acc ys
                      13            -> y : go acc ys
                      x | x == 7-y  -> y : go acc ys
                        | otherwise -> go (y:acc) ys
    go acc _ = acc

因此a)您可以在更小的空间中运行(除非消费者累积整个结果)和b)消费者无需等待整个列表被遍历即可开始工作。

当然,如果只有极少数甚至没有“good” y,可能不会有什么不同,如果消费者需要整个列表才能做任何事情。但通常情况下,这应该会有所改善。否则,在这个函数中没有什么可以做的,no_of_pebbles将是这里使用最多的资源。

如果move_ord可以使用非空primary_ordor调用secondary_ord,请使用包装器

move_ord xs (primary, secondary) = primary ++ go secondary xs
  where
    go acc ...  -- as above
于 2013-05-05T18:29:04.890 回答
1

我假设它move_ord开始被称为move_ord ys ([], []). 然后我们在Either.

import Data.Either

sorter :: (a -> Bool) -> [a] -> [Either a a]
sorter p = map go where go x = if p x then Left x else Right x

然后,

uncurry (++) 
. partitionEithers
. sorter (\x -> no_of_pebbles x == 13 || 7 - x == no_of_pebbles x) 
. filter (\x -> no_of_pebbles x != 0)

这仍然有点难看,因为我们一直no_of_pebbles在各个地方进行计算。出于文档目的,这可能没问题,但我们也可以预先计算no_of_pebbles.

uncurry (++)
. partitionEithers
. sorter (\(x, num) -> num == 13 || 7 - x == num)
. filter ((!=0) . snd)
. map (\x -> (x, no_of_pebbles x))
于 2013-05-05T17:18:58.490 回答
0

专业化。

当您使用文字常量时,编译器将推断默认整数类型而不是 Int。
然后你需要专门化你的函数的类型签名,就像这样。

move_ord :: [Int] -> ([Int], [Int]) -> ([Int], [Int])

记忆。

您的输入列表可以包含重复元素,那么两种策略是可能的。
记住您对 no_of_pebbles 的调用,它将节省您的提取计算,或者您可以在处理之前对输入列表的重复项进行排序和删除。

返回一个元组。

您将响应累积为一个元组,然后也许您应该按原样返回它。
试图将它的两个元素合并到函数中似乎超出了范围。
应该稍后在您的代码中进行管理,并且很高兴知道元组中的列表存储是常见的数据类型,称为 dlist。

于 2013-05-05T18:48:28.247 回答