如何避免Haskell中的stackoverflow错误

时间:2018-10-22 15:26:29

标签: haskell functional-programming stack-overflow

我要执行此功能:

呼叫 customPower 2 2 会回馈2 ^ 2 + 2 ^ 1 +1

呼叫 customPower 3 3 会回馈3 ^ 3 + 3 ^ 2 + 3 ^ 1 +1

这是我的代码:

remove_action('pre_get_posts','exclude_pages_from_search');

$hidePages = new WP_Query( array (
    'meta_key' => 'edit_screen_sitemap',
    'meta_value' => 'hide',
    'fields' => 'ids'
)); 

$hidePageIds = array($hidePages->posts);
$hidePageIdss = array($hidePages);

var_dump($hidePageIds); // array(1) { [0]=> array(0) { } }
var_dump($hidePageIdss); // displays query array

add_action('pre_get_posts','exclude_pages_from_search');

function exclude_pages_from_search($query) {
    if ( !is_admin() ) {

        if ( $query->is_main_query() ) {

            if ($query->is_search) {
                $query->set('post__not_in', array($hidePages->posts));
            }
        }
    }
}

它给了我堆栈溢出异常,我找不到错误在哪里。一切似乎都很好。

1 个答案:

答案 0 :(得分:9)

运算符的优先级低于函数调用的优先级,这意味着您的递归调用:

... + (customPower x y-1)

被解释为:

... + ((customPower x y)-1)

因此您继续使用 same 参数进行调用,因此递归永远不会结束。

我们可以通过在y-1中添加方括号来解决此问题:

customPower :: Int -> Int -> Int
customPower x y
    | y > 0 = x^y + customPower x (y-1)
    | otherwise = 1

通过此修改,我们不会陷入无限循环:

Prelude> customPower 5 3
156 

我们可以使用sum :: Num a => [a] -> amap :: (a -> b) -> [a] -> [b]来重写上面的内容,以单行代码实现:

customPower :: (Num a, Integral b) => a -> b -> a
customPower x y = sum (map (x^) [0..y])

或者我们可以使用iterate :: (a -> a) -> a -> [a]

customPower :: (Num a, Integral b) => a -> b -> a
customPower x y = sum (take (y+1) (iterate (x*) 1))

由于Haskell的懒惰,上述尝试仍可能会导致调用堆栈以y的值线性缩放:函数是@dfeuer所说的,不是尾递归函数,但是我们可以工作在这里有一个蓄能器:

customPower :: Int -> Int -> Int
customPower x = go 1
    where go a y | y > 1 = a
                 | otherwise = seq a (go (a+x^y) (y-1))

由于上述总和等于一个简单公式,我们甚至可以计算 O(y log x)中的值:

   y
.————            y+1
 ╲     i       x    - 1
 ╱    x    =   ————————
*————            x - 1
  i=0

因此我们可以使用以下方法计算值:

customPower :: (Integral a, Integral b) => a -> b -> a
customPower x y = div (x^(y+1) - 1) (x - 1)

这通常会更快,尽管在极少数情况下,结果时间x -1大于类型a的最大可表示数量,这将导致溢出并返回错误的数字