我在Haskell中实现了Smith-Waterman算法,但是我遇到了运行时错误:<<loop>>
在我的实现中,我正在尝试使用Haskell的惰性,因此我使用不可变数组resarray
来存储延迟和递归存根,这些存根也引用数组本身(在依赖链{{中} 1}}取决于resarray
,zippedList
取决于cellDef
,cell
取决于resarray
,取决于let arr = listArray (0,3) [0, arr ! 0, arr ! 1, arr ! 2 ]
)。每个单元格指的是索引较小的单元格,因此计算应该是可行的...尽管它不会那样。
作为概念证明,我在ghci中尝试了以下内容:
buildSWArray::
WordSequence ->
WordSequence ->
SWMatrix
buildSWArray ws1 ws2 = let
rows = arrLen ws1
cols = arrLen ws2
im = matToLinearIndex rows cols
mi = linToMatIndex rows cols
totsize = rows * cols
ixarr = [0 .. (totsize-1)]
cell i j
| i < 0 || j < 0 = 0
cell i j =
resarr ! (im i j )
cellDef k | k == 0 = (None,0)
cellDef k =
let
(i,j) = mi k
upwards = cell (i-1) j
leftwards = cell i (j-1)
diag = cell (i-1) (j-1)
-- One up if match, -5 if not match
c = if ws1 ! i == ws2 ! j then 1 else (-5)
hi = maximum [ 0, diag + c, upwards - 3, leftwards - 3]
in
-- Dirty way of guessing which one was picked up
case hi of
hi | hi == 0 -> ( None, 0)
hi | hi == upwards - 3 -> ( Upwards, hi)
hi | hi == leftwards - 3 -> ( Leftwards, hi )
hi | hi == diag + c -> (Diag, hi )
zippedList = [ cellDef k | k <- ixarr ]
resarr = IA.listArray (0,(totsize - 1)) [ score | (way,score) <- zippedList ]
wayarr = IA.listArray (0,(totsize - 1)) [ way | (way,score) <- zippedList ]
in
SWMatrix rows cols wayarr resarr
它有效。然而,由于某些未知原因,我的计算时间越长越严格。
这是我的代码(完整版本和测试脚本,here):
{{1}}
我该如何解决?
答案 0 :(得分:14)
你对模式匹配很严格,
resarr = IA.listArray (0,(totsize - 1)) [ score | (way,score) <- zippedList ]
wayarr = IA.listArray (0,(totsize - 1)) [ way | (way,score) <- zippedList ]
强制在构造时读取数组元素,但这不起作用。
简单示例:
module LazyArr where
import Data.Array.IArray
test :: Int -> (Array Int Int, Array Int Int)
test n =
let zippedList = map foo [0 .. n]
foo :: Int -> (Int,Int)
foo i
| i == 0 = (0,0)
| arrOne ! (i-1) < arrTwo ! (i-1) = (2,1)
| even i = (i,arrTwo ! (i-1))
| otherwise = (arrOne ! (i-1),i)
arrOne = listArray (0,n) $ map fst zippedList -- [a | (a,b) <- zippedList]
arrTwo = listArray (0,n) $ map snd zippedList -- [b | (a,b) <- zippedList]
in (arrOne, arrTwo)
有效,但使用列表推导而不是map fst
resp。 map snd
,它循环。
因此,使用lazier版本map fst zippedList
和map snd zippedList
应该可行(如同列表推导[way | ~(way,score) <- zippedList]
中的惰性模式一样),至少我没有看到依赖项中的其他问题
通过对上的模式匹配,cellDef k
必须进行足够的评估才能看到顶级构造函数确实是(,)
。为此,必须确定所采用的分支,并且需要检查先前元素的包含值。但是在创建数组时,尚无法获得这些数组。
然而,这并不重要。您所需要的只是没有依赖循环,并且每个链都会导致定义的基本情况。每个单元格指的是索引较小的单元格,因此计算应该是可行的