我的(更大)Haskell代码中有以下函数(有一些支持代码可以清楚说明是什么):
import qualified Data.Set as S
import qualified Data.IntMap.Strict as M
import Data.Ord
import Data.Monoid
data Atom = Neg { index :: Int }
| Pos { index :: Int }
deriving (Eq, Ord, Show, Read)
newtype Clause = Clause { atoms :: S.Set Atom }
deriving (Eq, Show, Read)
instance Ord Clause where
compare = comparing (Down . S.size . atoms) <> comparing atoms
newtype Form = Form { clauses :: S.Set Clause }
deriving (Eq, Ord, Show, Read)
type Interpretation = M.IntMap Bool
-- the function of interest
interpret :: Interpretation -> Form -> Maybe Bool
interpret interp = evalForm
where evalAtom x@(Pos _) = M.lookup (index x) interp
evalAtom x@(Neg _) = not <$> M.lookup (index x) interp
evalClause (Clause x)
| S.member (Just False) evaluated = Just False
| evaluated == S.singleton (Just True) = Just True
| otherwise = Nothing
where evaluated = S.map evalAtom x
evalForm (Form x)
| S.member (Just True) evaluated = Just True
| evaluated == S.singleton (Just False) = Just False
| otherwise = Nothing
where evaluated = S.map evalClause x
在分析了我的Haskell程序之后,我发现这个interpret
函数的分配占我程序中所有分配的近40%(以及大约40%的CPU工作)。
有什么方法可以减少interpret
的工作量或者分配的金额?这可能会让我获得巨大的性能提升(我可能真的需要,因为我需要多次运行此代码,以进行实验)。
答案 0 :(得分:2)
我会尝试S.foldr
。
从你的代码中看起来好像这些是AND子句,所以我假设一个空子句是假的。
evalClause (Clause x) = S.foldr f (Just False) $ S.map evalAtom x
where f b@(Just False) _ = b
f (Just True) y = y
f Nothing y@(Just False) = y
f Nothing y = Nothing
与evalForm
类似。
使用列表而不是集合也可能是有益的。实施的集合是严格的,并且(我认为)不会触发一些优化,如融合/砍伐森林等。列表是懒惰产生的,并且在这种代码中应该表现得更好。
evalClause (Clause x) = foldr f (Just False) . map evalAtom $ S.toList x
...
答案 1 :(得分:2)
观察:
Maybe Bool
只能有三个可能的值 - Nothing
,Just False
和Just True
。
evaluated
和evalClause
中的 evalForm
都有Set (Maybe Bool)
类型,可以用三位代表Int。
我会定义:
data MaybeBool = Nuthin | JustFalse | JustTrue
deriving (Eq, Ord, Enum, Bounded, Show, Read)
并更改intepret
的签名,返回MaybeBool
然后将evaluated
定义为这样的位集:
import Data.Bits
evaluated = foldl' combine 0 (map evalAtom (S.toList x))
where combine s a = s .|. (1 `shiftLeft` fromEnum a)
evaluated
将是0到7之间的Int,如果Nutin
在集合中,则设置为0,如果JustFalse
在集合中,则设置为位1,如果JustTrue
,则设置为位2 {1}}在集合中。这将消除计算中的集合分配。