Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.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_Recursion - Fatal编程技术网

在Haskell数组创建中允许哪些递归调用?

在Haskell数组创建中允许哪些递归调用?,haskell,recursion,Haskell,Recursion,作为使用Haskell数组的一个简短练习,我想实现一个给出前n个(奇数)素数的函数。下面的代码(使用GHC 7.10.3编译)在运行时产生循环错误。“Haskell的温和介绍”在数组创建中使用递归调用来计算斐波那契数(,13.2,下面的代码供参考),这很好。我的问题是: 这两种递归创建方法的区别在哪里?创建数组时通常允许哪些递归调用 我的代码: import Data.Array.Unboxed main = putStrLn $ show $ (primes 500)!500 --arbit

作为使用Haskell数组的一个简短练习,我想实现一个给出前n个(奇数)素数的函数。下面的代码(使用GHC 7.10.3编译)在运行时产生循环错误。“Haskell的温和介绍”在数组创建中使用递归调用来计算斐波那契数(,13.2,下面的代码供参考),这很好。我的问题是:

这两种递归创建方法的区别在哪里?创建数组时通常允许哪些递归调用

我的代码:

import Data.Array.Unboxed

main = putStrLn $ show $ (primes 500)!500 --arbitrary example


primes :: Int -> UArray Int Int
primes n = a
  where
    a = array (1,n) $ primelist 1 [3,5..]
    primelist i (m:ms) =
      if   all (not . divides m) [ a!j | j <- [1..(i-1)]]
      then (i ,m) : primelist (succ i) ms
      else primelist i ms
    divides m k = m `mod` k == 0
import Data.Array.unbox
main=putStrLn$show$(素数500)!500——任意示例
素数::Int->UArray Int
素数n=a
哪里
a=数组(1,n)$primelist 1[3,5..]
素数表i(m:ms)=
如果all(非.除m)[a!j | j数组Int
fibs n=a,其中a=数组(0,n)([(0,1),(1,1)]++

[(i,a!(i-2)+a!(i-1))| i更新:我想我终于明白发生了什么。
array
在列表元素上是懒惰的,但在脊椎上是不必要的严格

例如,这会导致
异常

test :: Array Int Int
test = array (1,2) ((1,1) : if test!1 == 1 then [(2,2)] else [(2,100)])
不像

test :: Array Int Int
test = array (1,2) ((1,1) : [(2, if test!1 == 1 then 2 else 100)])
因此,只要递归只影响值,它就可以工作

工作版本:

main :: IO ()
main = do
   putStrLn $ show $ (primes 500)!500 --arbitrary example

-- A spine-lazy version of array
-- Assumes the list carries indices lo..hi
arraySpineLazy :: (Int, Int) -> [(Int, a)] -> Array Int a
arraySpineLazy (lo,hi) xs = array (lo,hi) $ go lo xs
   where
   go i _ | i > hi = []
   go i ~((_,e):ys) = (i, e) : go (succ i) ys

primes :: Int -> Array Int Int
primes n = a
  where
    a :: Array Int Int
    a = arraySpineLazy (1,n) $ primelist 1 (2: [3,5..])
    primelist :: Int -> [Int] -> [(Int, Int)]
    primelist i _ | i > n = []
    primelist _ [] = [] -- remove warnings
    primelist i (m:ms) =
      if all (not . divides m) [ a!j | j <- [1..(i-1)]]
      then (i ,m) : primelist (succ i) ms
      else primelist i ms
    divides m k = m `mod` k == 0
这递归地定义了
x=0;y=0
。但是,要使递归工作,必须使该对是惰性的。否则,它将生成无限递归,如下所示:

let p = case p of (x,y) -> (0,x)
上面,
p
在暴露
(,)
对构造函数之前对自身进行求值,因此出现了一个无限循环

let p = (0, case p of (x,y) -> x)
将起作用,因为
p
在调用自身之前生成
(,)
。但是请注意,这依赖于构造函数
(,)
在返回之前不评估组件--它必须是惰性的,并且立即返回,而组件将在以后进行评估

在操作上,一对被构造为具有内部tho thunks:两个指向代码的指针,稍后将对结果进行计算。因此,这对指针实际上不是一对整数,而是一对指向整数的间接指针。这称为“装箱”,是实现惰性所必需的,即使它会带来一点计算成本


根据定义,未装箱的数据结构,如未装箱的数组,避免装箱,因此它们是严格的,而不是懒惰的,并且它们不能支持相同的递归方法。

由于斐波那契示例有效,这意味着数组具有正确的懒散属性。如果在代码示例中用数组替换UArray,则问题应该得到解决(和import Data.Array)。不幸的是,修改后的代码在运行时仍会产生循环错误。@sf1请参阅我上次的编辑。这比我想象的要微妙得多。
let p = case p of (x,y) -> (0,x)
let p = (0, case p of (x,y) -> x)