EDIT3:私は非常に長い入力リストInt
を処理するコードを書いていますが、数百の重複はありません。私はいくつかのアキュムレータ値を計算するために累積部分和を維持するために2つの補助リストを使用しています。私はここですべてのリストを捨てて、それを素晴らしい破壊的なループに変えたいと思います。私は全体のコードを必要としませんちょうどスケルトンコードは偉大な、読み取り/書き込みが2つの補助配列に行われ、いくつかの最終結果が返されます。今私が持っているものは、入力のために0.5時間実行されます。私はこれをC++でコーディングしました。同じ入力に対して90秒で動作します。このリストベースのコードを可変配列を使って翻訳するには?
私はこれを行う方法を全く理解できません。これは私が今持っているリストベースのコードです:(但し、下記の地図ベースのコードは明確である)
ins :: (Num b, Ord a) => a -> b -> [(a, b)] -> ([(a, b)], b)
ins n x [] = ([(n,x)], 0)
ins n x [email protected]((v, s):t) =
case compare n v of
LT -> ((n,s+x) : l , s)
EQ -> ((n,s+x) : t , if null t then 0 else snd (head t))
GT -> let (u,z) = ins n x t
in ((v,s+x):u,z)
これは、既知の長さの番号のリストを処理するために、ループ内で使用されていますこれは動作しますが、私はそれをスピードアップする必要が
scanl g (0,([],[])) ns -- ns :: [Int]
g ::
(Num t, Ord t, Ord a) =>
(t, ([(a, t)], [(a, t)])) -> a -> (t, ([(a, t)], [(a, t)]))
g (c,(a, b)) n =
let
(a2,x) = ins n 1 a
(b2,y) = if x>0 then ins n x b else (b,0)
c2 = c + y
in
(c2,(a2, b2))
(今foldlのためにそれを変更しました)。 Cでは、私はリストを(a,b)
の配列として保持します。バイナリ検索を使用して、n
以上のキーを持つ要素を検索します(ここで使用されるシーケンシャル検索ではなく)。インプレース更新を使用して上記のすべてのエントリを変更します。
私は本当に最終価値に興味があります。これはHaskellでどのように変更可能な配列で行われますか?
私は何かしようとしましたが、私がここで何をしているのかわからず、奇妙で非常に長いエラーメッセージ(「コンテキストから推論できません...」):
goarr top = runSTArray $ do
let sz = 10000
a <- newArray (1,sz) (0,0) :: ST s (STArray s Int (Integer,Integer))
b <- newArray (1,sz) (0,0) :: ST s (STArray s Int (Integer,Integer))
let p1 = somefunc 2 -- somefunc :: Integer -> [(Integer, Int)]
go1 p1 2 0 top a b
go1 p1 i c top a b =
if i >= top
then
do
return c
else
go2 p1 i c top a b
go2 p1 i c top a b =
do
let p2 = somefunc (i+1) -- p2 :: [(Integer, Int)]
let n = combine p1 p2 -- n :: Int
-- update arrays and calc new c
-- like the "g" function is doing:
-- (a2,x) = ins n 1 a
-- (b2,y) = if x>0 then ins n x b else (b,0)
-- c2 = c + y
go1 p2 (i+1) c2 top a b -- a2 b2??
これはまったく機能しません。私はdo表記法でループをエンコードする方法も知らない。助けてください。
UPD: 3倍遅く走る地図ベースのコード:
ins3 :: (Ord k, Num a) => k -> a -> Map.Map k a -> (Map.Map k a, a)
ins3 n x a | Map.null a = (Map.insert n x a , 0)
ins3 n x a = let (p,q,r) = Map.splitLookup n a in
case q of
Nothing -> (Map.union (Map.map (+x) p)
(Map.insert n (x+leftmost r) r) , leftmost r)
Just s -> (Map.union (Map.map (+x) p)
(Map.insert n (x+s) r) , leftmost r)
leftmost r | Map.null r = 0
| otherwise = snd . head $ Map.toList r
UPD2:文脈からのエラーメッセージは「推測できませんでした(NUM(STARRAY S1 IE))() filename.hs:417:11でリテラル「0」から生じる
return c
の中のgo1
の機能です。おそらくc
は配列であると予想されますが、2つの補助配列を使用して構築されたアキュムレータ値を返したいと思います。
EDIT3:私はクリスのアドバイスに従ってfoldl
とtake
でscanl
と(!!)
を交換してきた、そして今、それは正気経験的複雑さに一定の間隔で実行され、実際には0.5時間未満で終了すると予測されている - a.o.t. ... 3日間!私はもちろんそのことを知っていましたが、GHCが私のためにその材料を最適化してくれることを確信していました。違いがそれほどありません。、私は思った!そして、変更可能なアレイだけが助けになると感じました...バマー。
でも、C++は90秒で同じことをしますが、これを可変配列でコード化する方法をHaskellで学ぶことには大変感謝しています。
このコードは非常に難しいです。 –
後半はほとんど私が何をやっているのかわからないのでほとんど不器用です。最初の半分は作業コードであり、2つの補助リストを維持しながらループ内で何かを計算します。これは、高速化のために配列に変換したいものです。 – darveter
_first_半分は依然として難しいです。多分、私たちはいくつかのタイプシグネチャを取得できますか?またはいくつかのコメント? –