2014-11-14 2 views
2

В процессе обучения и экспериментирования использование Data.Vector.Unboxed.Mutable с runST придумал этот код:Haskell падает с runST и Data.Vector.Unboxed.Mutable

{-# LANGUAGE BangPatterns #-} 
import qualified Data.Vector.Unboxed.Mutable as UVM (unsafeNew, unsafeWrite, unsafeRead) 
import Control.Monad.ST 

test :: Int -> Int 
test len = runST $ do 
    vec <- UVM.unsafeNew (len - 1) 
    let 
     fill !i 
      | i >= len = sumVec 0 0 
      | otherwise = do 
       UVM.unsafeWrite vec i i 
       fill (i + 1) 
     sumVec !k !total 
      | k >= len = return total 
      | otherwise = do 
       x <- UVM.unsafeRead vec k 
       sumVec (k + 1) (total + x) 
    fill 0 

testParent = test 5 

Если я запускаю это, Haskell перестает работать. Я пришел к этому, пытаясь сделать эту работу:

test :: Int -> Int 
test len = do 
. 
. 
. 
testParent = runST $ test 5 

Но без успеха.

  • Зачем нужен Haskell (7.8.3) с предоставленным кодом?
  • Как я могу вычислить функцию test, используя runST, но за пределами test? Читал в this, но все еще не понял, почему он не работает.

ответ

4

В этой строке:

vec <- UVM.unsafeNew (len - 1) 

вы создаете вектор длины len-1. Но вы пишете индексы от 0 до len-1, поэтому вам нужен вектор длины len.

Смените это на len и оно будет работать.

Что касается вашего второго вопроса, то вы можете использовать runST так:

-- test now begins with the `do` statement 
test len = do 
    vec <- UVM.unsafeNew len 
    ... 

main = print $ runST $ test 5 

главное теперь, чтобы обернуть вызов, чтобы проверить в runST.

+0

Хорошо. Первая часть хорошая. Но, во-вторых, я не хочу этого на главном, я хочу его на другой функции (testParent), как развернуть эту монаду, чтобы получить 'int'? – OneEyeQuestion

+0

'runST' разворачивает значение; 'runST $ test 5' - это просто' Int', поэтому вы можете сказать такие вещи, как 'let x = 3 * (runST $ test 5)' – ErikR

+0

Почему тогда 'testParent = runST $ test 5' не компилируется? – OneEyeQuestion