Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.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 - Fatal编程技术网

Haskell 生成此数组时执行无限循环

Haskell 生成此数组时执行无限循环,haskell,Haskell,我实现了KMP算法的失败表 kmp s = b where a = listArray (0,length s-1) s b = 0:list 0 (tail s) list _ [] = [] list n (x:xs) | x==a!n = (n+1):list (n+1) xs | n > 0 = list (b!!(n-1)) (x:xs)

我实现了KMP算法的失败表

kmp s = b
    where a = listArray (0,length s-1) s
          b = 0:list 0 (tail s)
          list _ [] = [] 
          list n (x:xs) 
            | x==a!n    = (n+1):list (n+1) xs
            | n > 0     = list (b!!(n-1)) (x:xs)
            | otherwise = 0:list 0 xs
b
是一个列表,
b!!(n-1)
最后一行速度较慢,因此我希望加快速度,并执行了以下操作

kmp s = b
    where a = listArray (0,length s-1) s
          t = listArray (0,length s-1) b
          b = 0:list 0 (tail s)
          list _ [] = [] 
          list n (x:xs) 
            | x==a!n    = (n+1):list (n+1) xs
            | n > 0     = list (t!(n-1)) (x:xs)
            | otherwise = 0:list 0 xs
注:唯一的区别是更换
b通过
t
并声明
t
为从
b
生成的数组

对于相同的输入,原始代码有正确的输出,但新代码只输出


如何解决此问题?

您的问题是列表
b
需要数组
t
来确定其结构(长度)。但是数组
t
需要列表的长度才能存在:

listArray :: Ix i => (i,i) -> [e] -> Array i e
listArray (l,u) es = runST (ST $ \s1# ->
    case safeRangeSize (l,u)            of { n@(I# n#) ->
    case newArray# n# arrEleBottom s1#  of { (# s2#, marr# #) ->
    let fillFromList i# xs s3# | i# ==# n# = s3#
                               | otherwise = case xs of
            []   -> s3#
            y:ys -> case writeArray# marr# i# y s3# of { s4# ->
                    fillFromList (i# +# 1#) ys s4# } in
    case fillFromList 0# es s2#         of { s3# ->
    done l u n marr# s3# }}})
如您所见,首先分配一个适当大小的原始数组,然后用
arrelbottom
(这是一个
错误
调用,消息为undefined array element),然后遍历列表并将列表元素写入数组(列表元素可以毫无问题地引用数组值)。最后,数组被冻结。在冻结数组之前,不能从填充代码外部访问它(它基本上是一个
sts
计算)

最简单的修复方法是在
sts
monad中使用可变数组

kmp s = elems b
  where
    l = length s - 1
    a = listArray (0, l) s
    b = runSTArray $ do
           t <- newArray_ (0,l)
           writeArray t 0 0
           let fill _ _ [] = return t
               fill i n (x:xs)
                 | x == a!n = do
                        writeArray t i (n+1)
                        fill (i+1) (n+1) xs
                 | n > 0    = do
                        k <- readArray t (n-1)
                        fill i k (x:xs)
                 | otherwise = do
                        writeArray t i 0
                        fill (i+1) 0 xs
           fill 1 0 (tail s)
kmp s=elems b
哪里
l=长度s-1
a=listArray(0,l)s
b=星光大道$do
t0=do

k您的问题是列表
b
需要数组
t
来确定其结构(长度)。但是数组
t
需要列表的长度才能存在:

listArray :: Ix i => (i,i) -> [e] -> Array i e
listArray (l,u) es = runST (ST $ \s1# ->
    case safeRangeSize (l,u)            of { n@(I# n#) ->
    case newArray# n# arrEleBottom s1#  of { (# s2#, marr# #) ->
    let fillFromList i# xs s3# | i# ==# n# = s3#
                               | otherwise = case xs of
            []   -> s3#
            y:ys -> case writeArray# marr# i# y s3# of { s4# ->
                    fillFromList (i# +# 1#) ys s4# } in
    case fillFromList 0# es s2#         of { s3# ->
    done l u n marr# s3# }}})
如您所见,首先分配一个适当大小的原始数组,然后用
arrelbottom
(这是一个
错误
调用,消息为undefined array element),然后遍历列表并将列表元素写入数组(列表元素可以毫无问题地引用数组值)。最后,数组被冻结。在冻结数组之前,不能从填充代码外部访问它(它基本上是一个
sts
计算)

最简单的修复方法是在
sts
monad中使用可变数组

kmp s = elems b
  where
    l = length s - 1
    a = listArray (0, l) s
    b = runSTArray $ do
           t <- newArray_ (0,l)
           writeArray t 0 0
           let fill _ _ [] = return t
               fill i n (x:xs)
                 | x == a!n = do
                        writeArray t i (n+1)
                        fill (i+1) (n+1) xs
                 | n > 0    = do
                        k <- readArray t (n-1)
                        fill i k (x:xs)
                 | otherwise = do
                        writeArray t i 0
                        fill (i+1) 0 xs
           fill 1 0 (tail s)
kmp s=elems b
哪里
l=长度s-1
a=listArray(0,l)s
b=星光大道$do
t0=do

k这并没有直接回答您的问题,但提供了一个比使用
STArray
s的建议版本更简单的修复

该算法的命令式版本直接转换为不使用重复列表索引或状态的版本,只使用惰性数组构造:

import Data.Array.IArray

kmp :: String -> Array Int Int
kmp s = b
  where
    a :: Array Int Char
    a = listArray (0,l-1) s
    b = listArray (1,l) (0:map (\q -> f (b!(q-1)) q) [2..l])
    f k q
      | k > 0 && (a ! k) /= (a ! (q-1)) =
        f (b ! k) q
      | a ! k == a ! (q-1) = k + 1
      | otherwise = k
    l = length s

但是,我还没有对此进行基准测试。

这并没有直接回答您的问题,但提供了一个比使用
STArray
s的建议版本更简单的修复方法

该算法的命令式版本直接转换为不使用重复列表索引或状态的版本,只使用惰性数组构造:

import Data.Array.IArray

kmp :: String -> Array Int Int
kmp s = b
  where
    a :: Array Int Char
    a = listArray (0,l-1) s
    b = listArray (1,l) (0:map (\q -> f (b!(q-1)) q) [2..l])
    f k q
      | k > 0 && (a ! k) /= (a ! (q-1)) =
        f (b ! k) q
      | a ! k == a ! (q-1) = k + 1
      | otherwise = k
    l = length s

但是,我还没有对此进行基准测试。

教科书中的强制算法版本(例如,请参见CLRS)直接转换为快速版本(无
O(n^2)
lookups),只使用数组的惰性构造。另外,伯德的书《函数算法设计的珍珠》中有一个KMP的衍生版本,它不使用数组,但这看起来肯定与OP的算法有很大的不同。@Fixnum在
STArray
版本中没有O(n²),这是我所知的教科书算法的一个未经优化的版本,完全线性。当然,以后将数组转换为列表不是很有效,应该使用数组[实际上,从一开始就应该使用未绑定的数组]。对不起!我指的是OP对列表索引的抱怨,我错误地认为这会导致渐进式的减速。我只是想指出,您可以消除
(!!)
,而无需可变数组和对OP的代码进行侵入性较小的更改)。我明白了。对不起,误会了。但是我没有看到OP算法的入侵性改变,它是一个非常直接的端口,我不想改变结构。教科书中的命令式算法版本(例如,CLRS)直接转换为快速版本(no
O(n^2)
lookups),只使用数组的惰性构造。另外,伯德的书《函数算法设计的珍珠》中有一个KMP的衍生版本,它不使用数组,但这看起来肯定与OP的算法有很大的不同。@Fixnum在
STArray
版本中没有O(n²),这是我所知的教科书算法的一个未经优化的版本,完全线性。当然,以后将数组转换为列表不是很有效,应该使用数组[实际上,从一开始就应该使用未绑定的数组]。对不起!我指的是OP对列表索引的抱怨,我错误地认为这会导致渐进式的减速。我只是想指出,您可以消除
(!!)
,而无需可变数组和对OP的代码进行侵入性较小的更改)。我明白了。对不起,误会了。但是我没有看到OP算法的侵入性改变,它是一个非常直接的端口,我不想改变结构。