2016-08-13 1 views
1
{-# LANGUAGE ScopedTypeVariables,BangPatterns #-} 

import qualified Data.Attoparsec.Internal as I 
import qualified Data.Attoparsec.Internal.Types as T 
import qualified Data.Vector.Unboxed as UVec 
import qualified Data.Vector.Unboxed.Mutable as UMVec 
import qualified Data.Vector as Vec 
import qualified Data.Vector.Mutable as MVec 
import qualified Data.Text as Text 
import qualified System.IO.Unsafe as Unsafe 

import Control.Monad.ST 
import Control.Monad.Primitive 

type Parser = T.Parser 

manyCPSVec :: Parser Text.Text Char -> Parser Text.Text (Vec.Vector Char) 
manyCPSVec parser = T.Parser $ \t pos more lose_fin win_fin -> 
     let arr = Unsafe.unsafePerformIO (MVec.new 1024) in 
     loop 0 arr t pos more lose_fin win_fin where 
      loop i (arr :: MVec.MVector RealWorld Char) t pos more lose_fin win_fin = 
       T.runParser parser t pos more lose win where 
        win t !pos more (a :: Char) = 
        Unsafe.unsafePerformIO (MVec.write arr i a) -- Here is the problem 
        loop (i+1) arr t pos more lose_fin win_fin 
        lose t pos more _ _ = 
         --x <- Vec.freeze arr 
         win_fin t pos more (Vec.empty) 

main = print "Hello" 

私は効率のためにAttoparsecにいくつかのVector機能を入れようとしていますが、私は壁にぶつかりました。CPSスタイル関数で渡されたベクターを突然変異させる方法は?

AttoparsecがCPSを使用して書かれていない場合は、functional unfoldrを使用している可能性がありますが、これはオプションではありません。問題は、すべての呼び出しがここで末尾になければならず、関数の標準的な意味で関数が返されないため、配列をアキュムレータとして渡す必要があるということです。

私はSTモナドを使ってこれを試みましたが、それがうまくいかなかったときに私は上記を試みましたが、それでもうまくいきません。ハスケルの型システムは本当にここで私を殺しています。とにかくCPSでプログラミングするときに可変配列を編集することは可能ですか?

これをSTモナド内で実行することができれば、私はこれを二倍に感謝するでしょう。

しかし、配列以外のデータ構造を使用するように指示されている投稿は、削除されます。

+0

これは、リストを収集し、 'Vector.fromList'を使うよりも速くなるのでしょうか? – Michael

+0

私はあなたが 'ST'でこれを行う方法を見つけることができるはずだと思います。問題は部分的な結果を効率的に扱うことになりますが、それらを処理するための効率的な方法はないと思います。特に、部分的な結果が異なる入力で複数回再開できることを覚えていて、あまりにも多くの 'unsafePerformIO'があなたのコードを壊す可能性があります。 – dfeuer

+0

@Michaelええ、かなり。 10Mの整数を解析する場合、使用するデータ構造に違いがあります。ボックス化されたベクトルで[完成したパーサー](https://github.com/mrakgr/futhark/blob/parser_attempts/cps_parser_v5.hs)を使用すると、7.6sの10M intを扱います。ボックス化されていないパーサーでは、4秒でそれを行います。 boxed Vectorで拡張機能unfoldrを使用するだけで、2秒で動作します。 F#の 'ResizeArray'は1.2sでそれを行います。 [persistent vector](https://hackage.haskell.org/package/persistent-vector)は9.8でそれを行います。 F#ソリューションとは別に、彼らはすべて100Mでヒープを吹き飛ばします。リストは10Mよりずっと前にそれを行います。 –

答えて

0

私がこの記事を書いてから数分後、私は文法上の誤りを起こしました。

manyCPSVec :: Parser Text.Text Char -> Parser Text.Text (Vec.Vector Char) 
manyCPSVec parser = T.Parser $ \t pos more lose_fin win_fin -> 
     let arr = Unsafe.unsafePerformIO (MVec.new 1024) in 
     loop 0 arr t pos more lose_fin win_fin where 
      loop i (arr :: MVec.MVector RealWorld Char) t pos more lose_fin win_fin = 
       T.runParser parser t pos more lose win where 
        win t !pos more (a :: Char) = 
        Unsafe.unsafePerformIO $ do 
         MVec.write arr i a 
         return $ loop (i+1) arr t pos more lose_fin win_fin 
        lose t pos more _ _ = 
        Unsafe.unsafePerformIO $ do 
         x <- Vec.freeze arr 
         return $ win_fin t pos more x 

上記のタイプはokです。私は、Haskellのdoブロックの外側にある文をシーケンスできないことを忘れていました。

関連する問題