Haskell以任何方式改进此代码

时间:2013-05-05 16:56:43

标签: performance haskell

嘿,我已将此代码段实现为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)

这意味着在列表的前面放置具有特定卵石值(13和7-y == x)的移动。同时也过滤掉了0个鹅卵石的非法移动。

Pebbles存储为Int。 y是Int。

提前谢谢。

3 个答案:

答案 0 :(得分: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)消费者不需要等待整个列表被遍历才能开始工作。

当然,如果只有极少数甚至没有“好”的y,它可能没有区别,如果消费者需要整个列表,它才能做任何事情。但通常情况下,这应该会有所改善。否则,在此函数中没有太多可以完成的工作,no_of_pebbles将使用最多的资源。

如果可以使用非空move_ordprimary_ord调用secondary_ord,请使用包装

move_ord xs (primary, secondary) = primary ++ go secondary xs
  where
    go acc ...  -- as above

答案 1 :(得分: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))

答案 2 :(得分:0)

专业化。

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

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

记忆化

您的输入列表可以包含重复元素,然后可以采用两种策略 记住你对no_of_pebbles的调用,它会保存你提取计算,或者你可以在处理之前对输入列表的副本进行排序和删除。

返回一个元组。

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