I made a implementation of the KMP algorithm’s fail table.
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 is a list, and b!!(n-1) in the last line is slow, therefore I wish to speed it up and did the following.
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
Note the only difference is to replace b!! by t! and declares t to be the array generated from b.
For the same input, the original code have the correct output, but the new one just outputs <<loop>>.
How can one fix this problem?
Your problem is that the list
bneeds the arraytto determine its structure (length). But the arraytneeds the length of the list before it exists:As you can see, first a raw array of appropriate size is allocated, then it is filled with
arrEleBottom(which is anerrorcall with message undefined array element), then the list is traversed and the list elements are written to the array (the list elements can refer to array values without problem). Then, finally, the array is frozen. Before the array is frozen, it cannot be accessed from outside the filling code (it’s basically anST scomputation).The simplest way to fix it is IMO to use a mutable array in an
ST smonad,is a very direct (and a bit inefficient) translation of the code.