Haskell平台中的许多函数的实现中有一个非常常见的模式困扰我,但我无法找到解释。这是关于使用嵌套函数进行优化。Haskell平台:嵌套函数和优化
原因在where子句中嵌套函数时,他们的目标是使尾递归是很清楚,我(在length),但目的是什么,当内部函数具有完全相同的类型作为最高一级?它发生,例如,在Data.Set
module的许多功能,如下列之一:
-- | /O(log n)/. Is the element in the set?
member :: Ord a => a -> Set a -> Bool
member = go
where
STRICT_1_OF_2(go)
go _ Tip = False
go x (Bin _ y l r) = case compare x y of
LT -> go x l
GT -> go x r
EQ -> True
#if __GLASGOW_HASKELL__ >= 700
{-# INLINABLE member #-}
#else
{-# INLINE member #-}
#endif
我怀疑它可能有一些做记忆化,但我不知道。
编辑:由于dave4420建议严格,这里是为STRICT_1_OF_2
宏定义,可以在同一模块中找到:
-- Use macros to define strictness of functions.
-- STRICT_x_OF_y denotes an y-ary function strict in the x-th parameter.
-- We do not use BangPatterns, because they are not in any standard and we
-- want the compilers to be compiled by as many compilers as possible.
#define STRICT_1_OF_2(fn) fn arg _ | arg `seq` False = undefined
我了解这个宏的作品,但是我仍然不明白为什么go
连同STRICT_1_OF_2(go)
不应该被移到顶层而不是member
。
也许这不是因为优化,而仅仅是因为文体选择?
编辑2:我增加了INLINABLE
和INLINE
部从所述一组模块。我没有想到,他们乍一看可能会有什么用处。
我怀疑这与严格分析有关:编译器应该推断出'member'的第一个参数必须被评估,但'go'的第一个参数总是被评估过。但我不确定。 – dave4420 2012-03-18 10:23:46
@ dave4420:谢谢你的建议。我用一些关于函数严格性的更多信息更新了我的问题,我希望这会有所帮助。 – 2012-03-18 10:51:45
我认为这纯粹是一个风格问题。但是你可以通过'go'中的'x'释放一些微小的增益。我不喜欢这样写蜜蜂的风格,因为它似乎暗示x在每次迭代中都会被seq:ed。另外,当它不一定是(但那很小)时,它在'x'中使成员严格。 – augustss 2012-03-18 11:24:16