Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 如何实现惰性常数空间三分函数?_Haskell_Lazy Evaluation_Ghc - Fatal编程技术网

Haskell 如何实现惰性常数空间三分函数?

Haskell 如何实现惰性常数空间三分函数?,haskell,lazy-evaluation,ghc,Haskell,Lazy Evaluation,Ghc,我已经概括了现有的数据.List.partition实现 partition :: (a -> Bool) -> [a] -> ([a],[a]) partition p xs = foldr (select p) ([],[]) xs where -- select :: (a -> Bool) -> a -> ([a], [a]) -> ([a], [a]) select p x ~(ts,fs) | p x = (x

我已经概括了现有的
数据.List.partition
实现

partition :: (a -> Bool) -> [a] -> ([a],[a])
partition p xs = foldr (select p) ([],[]) xs
  where
    -- select :: (a -> Bool) -> a -> ([a], [a]) -> ([a], [a])
    select p x ~(ts,fs) | p x       = (x:ts,fs)
                        | otherwise = (ts, x:fs)
到一个“三分区”函数

但是现在我在使用
ghc-O1
编译时遇到了一个令人困惑的行为,'foo'和'bar'函数在恒定空间中工作,但是
doo
函数会导致空间泄漏

foo xs = xs1
  where
    (xs1,_,_) = ordPartition (flip compare 0) xs

bar xs = xs2
  where
    (_,xs2,_) = ordPartition (flip compare 0) xs

-- pass-thru "least" non-empty partition
doo xs | null xs1  = if null xs2 then xs3 else xs2
       | otherwise = xs1
  where
    (xs1,xs2,xs3) = ordPartition (flip compare 0) xs


main :: IO ()
main = do
    print $ foo [0..100000000::Integer] -- results in []
    print $ bar [0..100000000::Integer] -- results in [0]
    print $ doo [0..100000000::Integer] -- results in [0] with space-leak
所以我现在的问题是,

  • 由于
    foo
    bar
    没有出现这样的空间泄漏,我觉得奇怪的是
    doo
    中的空间泄漏是什么原因?及

  • 是否有一种实现
    ordPartition
    的方法,当在
    doo
    等函数的上下文中使用时,它以恒定的空间复杂度执行


  • 这不是空间泄漏。要确定组件列表是否为空,必须遍历整个输入列表,如果为空,则构建其他组件列表(如thunks)。在
    doo
    的情况下,
    xs1
    是空的,所以在决定输出什么之前必须构建整个东西


    这是所有分区算法的一个基本属性,如果其中一个结果为空,并且作为一个条件检查其是否为空,则在遍历整个列表之前,该检查无法完成。

    谢谢,但是我有一个额外的问题仍然让我困惑:如果我有一个定义为
    baz xs=(xs1,xs2)的
    baz xs=(xs1,xs2,xs3)=ordPartition(翻转比较0)xs
    ,为什么需要保留
    \u xs3
    (当
    foo
    bar
    不需要时)的值呢。由于结果决不取决于
    xs3
    ,因此这一点可以忽略。选择器thunk优化可能不会启动,并且通过保持活动的元组引用了
    \u xs3
    ,但这是一个意外。
    doo
    中的问题是需要
    xs1
    来找出结果是什么。在这个问题得到回答之前,任何东西都不能因为可能需要而放弃。而且,如本例中所示,如果在处理所有内容之前无法回答该问题,则必须保留结果可能需要的所有内容;如果我将
    (,)
    构造函数更改为
    (++)
    应用程序,或者如果我将bang模式添加到
    xs1
    xs2
    中,我看到的thunk将被避免。。。这值得作为ghc bug报告报告吗?报告过多比未报告的bug要好。但是已经有一些与此相关的票证,所以您可以搜索并查看是否最好对现有票证作出响应。但是,如果是回归,一定要打开一张新票。@is7s
    -O2
    在这里没有区别;我想部分原因是
    (a,b)
    仍然是由两个惰性值
    a
    b
    组成的,不清楚以后实际需要哪个值。。。
    foo xs = xs1
      where
        (xs1,_,_) = ordPartition (flip compare 0) xs
    
    bar xs = xs2
      where
        (_,xs2,_) = ordPartition (flip compare 0) xs
    
    -- pass-thru "least" non-empty partition
    doo xs | null xs1  = if null xs2 then xs3 else xs2
           | otherwise = xs1
      where
        (xs1,xs2,xs3) = ordPartition (flip compare 0) xs
    
    
    main :: IO ()
    main = do
        print $ foo [0..100000000::Integer] -- results in []
        print $ bar [0..100000000::Integer] -- results in [0]
        print $ doo [0..100000000::Integer] -- results in [0] with space-leak